2012-11-19 39 views
4

我的应用程序中有一个RichTextBox,它在某些事件上获取新内容。
添加新内容时,如果滚动在底部之前,我想滚动到底部,
我该怎么做?
更具体地说,给我麻烦的部分是确定滚动位置。
WPF RichTextBox的有条件滚动?

如果很重要,RichTextBox正在使用默认样式和模板,几个画笔已更改或设置为空,垂直滚动条可见性为自动且为只读。

+0

您可以将VerticalOffset与ViewportHeight进行比较吗? – Paparazzi

回答

3

如果你想要一个富文本框新增加的文本自动滚动仅在滚动条一直拖到底部添加下面的类到您的项目

public class RichTextBoxThing : DependencyObject 
{ 
    public static bool GetIsAutoScroll(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsAutoScrollProperty); 
    } 

    public static void SetIsAutoScroll(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsAutoScrollProperty, value); 
    } 

    public static readonly DependencyProperty IsAutoScrollProperty = 
     DependencyProperty.RegisterAttached("IsAutoScroll", typeof(bool), typeof(RichTextBoxThing), new PropertyMetadata(false, new PropertyChangedCallback((s, e) => 
      { 
       RichTextBox richTextBox = s as RichTextBox; 
       if (richTextBox != null) 
       { 
        if ((bool)e.NewValue) 
         richTextBox.TextChanged += richTextBox_TextChanged; 
        else if ((bool)e.OldValue) 
         richTextBox.TextChanged -= richTextBox_TextChanged; 

       } 
      }))); 

    static void richTextBox_TextChanged(object sender, TextChangedEventArgs e) 
    { 
     RichTextBox richTextBox = sender as RichTextBox; 
     if ((richTextBox.VerticalOffset + richTextBox.ViewportHeight) == richTextBox.ExtentHeight || richTextBox.ExtentHeight < richTextBox.ViewportHeight) 
      richTextBox.ScrollToEnd(); 
    } 
} 

然后在您想要的自动滚动行为的任何格式文本框添加IsAutoSroll财产

<RichTextBox ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" local:RichTextBoxThing.IsAutoScroll="True"/> 
+0

与其他答案相同。滚动条刚出现时不起作用。 – Vercas

+0

我已编辑好照顾启动案例 – Andy

+0

谢谢!它的工作原理与我现在所期望的完全相同。我比其他人更喜欢这个解决方案,因为它也给了我一个使用附加属性的例子,并展示了我稍后可以使用的这个控件的一些属性。我以前不知道该找什么。 – Vercas

1

基本上可以做到以下几点:获取滚动条,并订阅Value,MaximumMinimum(它们都是依赖项属性)的更改。通过这种方式,您可以通过在需要时将Value设置为Maximum来控制代码隐藏的位置。

现在,你如何访问滚动条?有几种方法。如果您确定哪一个是您的RichTextBox的控件模板,您可以使用GetTemplateChild(name)(您通过检查例如Blend中的模板来获得名称)。如果你不确定,你应该更好地创建自己的模板(再次,Blend会给你一个很好的模板开始),并将其应用到你感兴趣的RichTextBox

0

试试这个扩展m ethod:

public static class RichTextBoxExtensions 
{ 
    public static void ScrollIfNeeded(this RichTextBox textBox) 
    { 
     var offset = textBox.VerticalOffset + textBox.ViewportHeight; 
     if (Math.Abs(offset - textBox.ExtentHeight) > double.Epsilon) return; 
     textBox.ScrollToEnd(); 
    } 
} 

而且使用这样的:

textBox.AppendText(// Very long text here); 
textBox.ScrollIfNeeded(); 

编辑:另类包括滚动至底部时滚动条变为可见:

public static class RichTextBoxExtensions 
{ 
    public static void ScrollIfNeeded(this RichTextBox textBox) 
    { 
     var offset = textBox.VerticalOffset + textBox.ViewportHeight; 
     if (Math.Abs(offset - textBox.ExtentHeight) <= double.Epsilon) 
     { 
      textBox.ScrollToEnd(); 
     } 
     else 
     { 
      var contentIsLargerThatViewport = textBox.ExtentHeight > textBox.ViewportHeight; 
      if (Math.Abs(textBox.VerticalOffset - 0) < double.Epsilon && contentIsLargerThatViewport) 
      { 
       textBox.ScrollToEnd(); 
      } 
     } 
    } 
} 
+0

在滚动条可见之前它不起作用。(在内容大于可用空间之前) – Vercas

+0

不,因为在滚动条可见之前,“VerticalOffset”是0.你说你只希望它滚动到底部,如果它已经在底部... – khellang

+0

@Vercas查看修订后的答案... – khellang

3

简单多条件滚动VerticalOffset + ViewportHeight >= ExtentHeight

示例:

bool shouldScroll = rtbx.VerticalOffset + rtbx.ViewportHeight >= 
        rtbx.ExtentHeight; 

// changes to RichTextBox 
// ... 

if(shouldScroll) rtbx.ScrollToEnd(); 

也适用于'滚动条刚出现'的情况。

+0

这个效果很好,但由于您比较可能相等的双倍数,所以您应该在比较中引入一个“epsilon”。基本上我做了'rtbx.VerticalOffset + rtbx.ViewportHeight> = rtbx.ExtentHeight - 1.0;'它运作良好。我仍然投票,因为这节省了我一些时间! – Benlitz