Многострочное текстовое поле с автоматической вертикальной прокруткой - PullRequest
41 голосов
/ 20 января 2012

Есть много похожих вопросов по интернету, в том числе и по SO, но предлагаемые решения не работают в моем случае.Сценарий: в xaml

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

есть текстовое поле журнала. В коде есть методы, которые делают некоторую работу и добавляют несколько многострочных (может быть, проблема?) Сообщений в это текстовое поле:

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
}

Необходимо прокрутить текстовое поле до конца после того, как все действия будут выполнены.Пробовал ScrollToEnd (), ScrollToLine, обтекание текстового поля в обходы ScrollViewer, Selection и Caret, присоединяя ScrollToEnd к TextChanged.Ничего из этого не работает, после того, как строки выполнения, которые переполняют высоту текстового поля, все еще должны быть прокручены вручную.Извините за дублированный вопрос, я думаю, что я пропускаю некоторые незначительные проблемы, которые могут быть быстро решены кем-то, у кого есть новое видение проблемы.Заранее спасибо.

Ответы [ 4 ]

80 голосов
/ 20 января 2012

Согласно этому вопросу: TextBox.ScrollToEnd не работает, когда TextBox находится на неактивной вкладке

Вы должны сфокусировать текстовое поле, обновить позицию каретки изатем прокрутите до конца:

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

РЕДАКТИРОВАТЬ

Пример TextBox:

<TextBox TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" 
         AcceptsReturn="True" Name="textBox"/>
17 голосов
/ 13 февраля 2014

Если вы сделаете это простым пользовательским элементом управления, вам не понадобится какой-либо код для прокрутки.

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();
    }

}

Если вы используете WPF, было бы гораздо лучше использовать привязку, а не передавать текстовое поле в коде позади.

4 голосов
/ 03 августа 2018

Если вам не очень нравится код позади, вот 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)
            {
                textbox.TextChanged += (s, ee)=> AutoScrollToEnd(s, ee, textbox);
            }
        }

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

А затем в вашем xaml просто сделайте:

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

Только не забудьте добавить в начало вашего файла xaml

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

И вуаля

2 голосов
/ 20 ноября 2013

Спасибо!Я добавил это, чтобы запомнить первоначальный фокус:

var oldFocusedElement = FocusManager.GetFocusedElement(this);

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

FocusManager.SetFocusedElement(this, oldFocusedElement);
...