wpf 具有自动垂直滚动的多行文本框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8938775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:15:04  来源:igfitidea点击:

Multiline Textbox with automatic vertical scroll

wpftextboxmultilineautoscroll

提问by Jaded

There are a lot of similiar questions over internet, on SO included, but proposed solutions doesn't work in my case. Scenario : there is a log textbox in xaml

互联网上有很多类似的问题,包括在内,但提出的解决方案在我的情况下不起作用。场景:xaml 中有一个日志文本框

 <TextBox Name="Status"
          Margin="5"
          Grid.Column="1"
          Grid.Row="5"
          HorizontalAlignment="Left"
          VerticalAlignment="Top"
          Width="600"
          Height="310"/>

There are methods in code-behind that do some work and add some multiline (maybe that's the problem?) messages into this textbox:

代码隐藏中有一些方法可以做一些工作并将一些多行(也许这就是问题?)消息添加到此文本框中:

private static void DoSomeThings(TextBox textBox)
{
   // do work
   textBox.AppendText("Work finished\r\n"); // better way than Text += according to msdn
   // do more
   textBox.AppendText("One more message\r\n");
   ...
}

private static void DoSomething2(TextBox textBox)
{
   // same as first method
}

Need to scroll to bottom of textbox after all actions take place. Tried ScrollToEnd(), ScrollToLine, wrapping textbox into ScrollViewer, Selection and Caret workarounds, attaching ScrollToEnd to TextChanged. None of this works, after execution lines that overflow textbox height still need to be scrolled to manually. Sorry for duplicate question, i guess i'm missing some minor issues that can be resolved quickly by someone that has fresh vision on the problem. Thanks in advance.

需要在所有操作发生后滚动到文本框底部。尝试了 ScrollToEnd()、ScrollToLine、将文本框包装到 ScrollViewer、Selection 和 Caret 解决方法,将 ScrollToEnd 附加到 TextChanged。这些都不起作用,在溢出文本框高度的执行行后仍然需要手动滚动。对不起,重复的问题,我想我错过了一些小问题,可以由对问题有新见解的人快速解决。提前致谢。

回答by Adrian Faciu

According to this question: TextBox.ScrollToEnd doesn't work when the TextBox is in a non-active tab

根据这个问题:TextBox.ScrollToEnd 在 TextBox is in a non-active tab 时不起作用

You have to focus the text box, update the caret position and then scroll to end:

您必须聚焦文本框,更新插入符号位置,然后滚动到结尾:

Status.Focus();
Status.CaretIndex = Status.Text.Length;
Status.ScrollToEnd();

EDIT

编辑

Example TextBox:

示例文本框:

<TextBox TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" 
         AcceptsReturn="True" Name="textBox"/>

回答by Lee Willis

If you make it into a simple custom control then you don't need any code behind to do the scrolling.

如果你把它变成一个简单的自定义控件,那么你不需要任何背后的代码来进行滚动。

public class ScrollingTextBox : TextBox {

    protected override void OnInitialized (EventArgs e) {
        base.OnInitialized(e);
        VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
        HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
    }

    protected override void OnTextChanged (TextChangedEventArgs e) {
        base.OnTextChanged(e);
        CaretIndex = Text.Length;
        ScrollToEnd();
    }

}

If you're using WPF it would be far better to use binding rather than passing the text box around in the code behind.

如果您使用 WPF,最好使用绑定而不是在后面的代码中传递文本框。

回答by yan yankelevich

If you don't like code behind to much, here is an AttachedProperty that will do the trick :

如果您不太喜欢背后的代码,这里有一个可以解决问题的 AttachedProperty:

namespace YourProject.YourAttachedProperties
{

    public class TextBoxAttachedProperties
    {

        public static bool GetAutoScrollToEnd(DependencyObject obj)
        {
            return (bool)obj.GetValue(AutoScrollToEndProperty);
        }

        public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
        {
            obj.SetValue(AutoScrollToEndProperty, value);
        }

        // Using a DependencyProperty as the backing store for AutoScrollToEnd.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AutoScrollToEndProperty =
        DependencyProperty.RegisterAttached("AutoScrollToEnd", typeof(bool), typeof(TextBoxAttachedProperties), new PropertyMetadata(false, AutoScrollToEndPropertyChanged));

        private static void AutoScrollToEndPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if(d is TextBox textbox && e.NewValue is bool mustAutoScroll && mustAutoScroll)
            {
                textbox.TextChanged += (s, ee)=> AutoScrollToEnd(s, ee, textbox);
            }
        }

        private static void AutoScrollToEnd(object sender, TextChangedEventArgs e, TextBox textbox)
        {
            textbox.ScrollToEnd();
        }
    }
}

And then in your xaml just do :

然后在您的 xaml 中执行以下操作:

<TextBox
    AcceptsReturn="True"
    myAttachedProperties:TextBoxAttachedProperties.AutoScrollToEnd="True"/>

Just don't forget to add at the top of your xaml file

只是不要忘记在 xaml 文件的顶部添加

xmlns:myAttachedProperties="clr-namespace:YourProject.YourAttachedProperties"

And voila

回答by Darko D.

Thanks! I have added this to remember the original focus:

谢谢!我添加了这个以记住最初的重点:

var oldFocusedElement = FocusManager.GetFocusedElement(this);

this.textBox.Focus();
this.textBox.CaretIndex = this.textBox.Text.Length;
this.textBox.ScrollToEnd();

FocusManager.SetFocusedElement(this, oldFocusedElement);