Silverlight 4 RichTextBox прокрутить вниз - PullRequest
2 голосов
/ 25 августа 2011

Я пишу приложение для чата с Silverlight. Я добавляю содержимое динамически в поле расширенного текста, и мне нужно прокрутить его вниз, чтобы показать последние сообщения. Но нет способа сделать это. Вся документация / коды, которые я нашел в интернете, старые.

Любое решение будет с радостью принято.

Ответы [ 3 ]

4 голосов
/ 27 августа 2011

Я долго боролся с этим в собственном приложении. Метод Dispatcher.BeginInvoke не был для меня надежным; иногда он прокручивается до дна, а иногда нет. Единственный способ заставить его работать - это вставить два вызова Dispatcher.BeginInvoke друг в друга, но мне не понравилось это решение.

Вместо использования Dispatcher я злоупотребляю обработчиками событий. В этом примере текстовое поле будет прокручиваться вниз, только если оно было там во время добавления нового Inline (полезное поведение для окон чата, позволяющее пользователям читать предыдущие сообщения, если они этого хотят). Вы можете передать объект 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);
            }
        }
    }
}
3 голосов
/ 23 февраля 2012

Ну, вам не нужны ни методы расширения, ни диспетчеры. Самый простой способ прокрутить элемент управления RichTexBox вниз:

textBox.Selection.Select (textBox.ContentEnd, textBox.ContentEnd);

Подобным образом можно добиться поведения «прокрутка вверх».

Надеюсь, это поможет.

3 голосов
/ 25 августа 2011

Вам нужно выкопать ScrollViewer, который является частью шаблона RichTextBox.Вы можете сделать это с помощью некоторого кода, основанного на 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 помещает в очередь остальную часть кода в диспетчере потоков пользовательского интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...