Silverlight 4 RichTextBox滚动到底部
本文关键字:底部 滚动 RichTextBox Silverlight | 更新日期: 2023-09-27 18:06:32
我正在用Silverlight编写一个聊天应用程序。我正在动态地将内容添加到富文本框中,我需要向下滚动以显示最后的消息。但这是不可能的。我在网上找到的所有文档/代码都是旧的。
任何方案我们都乐意接受。
我在自己的应用程序中为此挣扎了很长时间。调度程序。BeginInvoke方法对我来说不可靠;有时它会滚动到底部,有时则不会。使其工作的唯一方法是嵌套两个Dispatcher。BeginInvoke在彼此内部调用,但我不喜欢这个解决方案。
我没有使用Dispatcher,而是滥用事件处理程序。在本例中,文本框只有在添加新的Inline时才会滚动到底部(这是聊天框的一个有用行为,允许用户在需要时阅读以前的消息)。你可以传递一个Run对象作为内联参数。
private void AddInline(Inline inline)
{
var viewer = textBox.GetChildByType<ScrollViewer>(item => item.Name == "ContentElement") as ScrollViewer;
bool scrollToBottom = viewer.VerticalOffset == viewer.ScrollableHeight;
// Creating the paragraph isn't necessary.
// In my own application, I only add a single paragraph to the RichTextBox that displays my chat messages.
// Then I just add new Inlines to the single paragraph.
Paragraph p = new Paragraph();
p.Inlines.Add(inline);
if (scrollToBottom)
textBox.LayoutUpdated += ScrollRichTextBoxToBottom;
// Adding the paragraph triggers a layout update.
// In the LayoutUpdated handler, the viewer will be scrolled to the bottom, triggering a second layout pass.
textBox.Blocks.Add(p);
}
private void ScrollRichTextBoxToBottom(object sender, EventArgs e)
{
// The LayoutUpdated handler needs to be removed, otherwise the RichTextBox becomes unscrollable.
textBox.LayoutUpdated -= ScrollRichTextBoxToBottom;
var viewer = textBox.GetChildByType<ScrollViewer>(item => item.Name == "ContentElement") as ScrollViewer;
viewer.ScrollToVerticalOffset(viewer.ScrollableHeight);
}
注意:GetChildByType只是一个扩展方法来获得ScrollViewer。(我没有创建这个扩展方法)
public static class Extensions
{
public static T GetChildByType<T>(this UIElement element, Func<T, bool> condition)
where T : UIElement
{
List<T> results = new List<T>();
GetChildrenByType<T>(element, condition, results);
if (results.Count > 0)
return results[0];
else
return null;
}
private static void GetChildrenByType<T>(UIElement element, Func<T, bool> condition, List<T> results)
where T : UIElement
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
UIElement child = VisualTreeHelper.GetChild(element, i) as UIElement;
if (child != null)
{
T t = child as T;
if (t != null)
{
if (condition == null)
results.Add(t);
else if (condition(t))
results.Add(t);
}
GetChildrenByType<T>(child, condition, results);
}
}
}
}
您需要挖掘出作为RichTextBox模板一部分的ScrollViewer。您可以在一些基于VisualTreeHelper
的代码的帮助下做到这一点。在这里获得我的VisualTreeEnumeration
类的代码。
现在在你的项目中使用这个类,你可以这样做:-
ScrollViewer sv = rtb.Descendents().OfType<ScrollViewer>().FirstOrDefault();
完整的示例
创建一个新的应用程序并包含VisualTreeEnumeration
类
主页。Xaml使用以下Xaml:-
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<RichTextBox x:Name="rtb" />
<Button Content="Click Me" Click="Button_Click" Grid.Row="1" />
</Grid>
在后面的代码中添加:-
int i = 0;
private void Button_Click(object sender, RoutedEventArgs e)
{
Paragraph p = new Paragraph();
p.Inlines.Add(new Run() { Text = "Hello " + (i++).ToString() });
rtb.Blocks.Add(p);
Dispatcher.BeginInvoke(() =>
{
ScrollViewer sv = rtb.Descendents().OfType<ScrollViewer>().FirstOrDefault();
sv.ScrollToVerticalOffset(sv.ScrollableHeight);
sv.UpdateLayout();
});
}
注意,使用BeginInvoke允许RTB在添加文本后对自己进行排序。使用BeginInvoke将UI线程分派器上的其余代码排队。
好吧,您既不需要扩展方法,也不需要分派器。将RichTexBox控件滚动到底部的最简单方法如下:
textBox.Selection.Select(文本框。ContentEnd textBox.ContentEnd);
你可以用类似的方式实现"滚动到顶部"的行为。
希望有帮助。