[英]Silverlight 4 RichTextBox scroll to bottom
我正在使用Silverlight編寫聊天應用程序。 我將內容動態添加到富文本框中,我需要向下滾動以顯示最后的消息。 但是沒有辦法做到這一點。 我在互聯網上找到的所有文檔/代碼都是舊的。
任何解決方案都會很樂意接受。
在我自己的應用程序中,我很長時間都在努力。 Dispatcher.BeginInvoke方法對我來說不可靠; 有時它會滾動到底部,有時則不會。 讓它工作的唯一方法是在彼此內部嵌入兩個Dispatcher.BeginInvoke調用,但我不喜歡這個解決方案。
我濫用事件處理程序,而不是使用Dispatcher。 在此示例中,只有在添加新內聯時,文本框才會滾動到底部(聊天框的有用行為,允許用戶在需要時閱讀以前的消息)。 您可以將Run對象作為Inline參數傳遞。
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
類。
在MainPage.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(textBox.ContentEnd,textBox.ContentEnd);
您可以以類似的方式實現“滾動到頂部”行為。
希望有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.