onsdag 3 oktober 2012

WPF: Automatically scrolling/autoscrolling TextBox for MVVM pattern

If we want a TextBox to automatically scroll to the end and not make a new control inheriting from TextBox or use the view's code-behind we can create an attached property.

First we make a class like so:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace NameSpace
{
    public class TextBoxAutomaticScrollingExtension
    {
        private static readonly Dictionary<TextBox, TextBoxScrollingTrigger> _textBoxesDictionary = 
            new Dictionary<TextBox, TextBoxScrollingTrigger>();

        public static readonly DependencyProperty ScrollOnTextChangedProperty =
            DependencyProperty.RegisterAttached(
                "ScrollOnTextChanged",
                typeof (bool),
                typeof (TextBoxAutomaticScrollingExtension),
                new UIPropertyMetadata(false, OnScrollOnTextChanged));

        private static void OnScrollOnTextChanged(DependencyObject dependencyObject,
                                                  DependencyPropertyChangedEventArgs e)
        {
            var textBox = dependencyObject as TextBox;
            if (textBox == null)
            {
                return;
            }

            bool oldValue = (bool) e.OldValue;
            bool newValue = (bool) e.NewValue;
            if (newValue == oldValue)
            {
                return;
            }

            if (newValue)
            {
                textBox.Loaded += OnTextBoxLoaded;
                textBox.Unloaded += OnTextBoxUnloaded;
            }
            else
            {
                textBox.Loaded -= OnTextBoxLoaded;
                textBox.Unloaded -= OnTextBoxUnloaded;

                if (_textBoxesDictionary.ContainsKey(textBox))
                {
                    _textBoxesDictionary[textBox].Dispose();
                }
            }
        }

        private static void OnTextBoxLoaded(object sender, RoutedEventArgs e)
        {
            var textBox = (TextBox) sender;
            textBox.Loaded -= OnTextBoxLoaded;
            _textBoxesDictionary[textBox] = new TextBoxScrollingTrigger(textBox);
        }

        private static void OnTextBoxUnloaded(object sender, RoutedEventArgs e)
        {
            var textBox = (TextBox) sender;
            textBox.Unloaded -= OnTextBoxUnloaded;
            _textBoxesDictionary[textBox].Dispose();
        }

        public static bool GetScrollOnTextChanged(DependencyObject dependencyObject)
        {
            return (bool) dependencyObject.GetValue(ScrollOnTextChangedProperty);
        }

        public static void SetScrollOnTextChanged(DependencyObject dependencyObject, bool value)
        {
            dependencyObject.SetValue(ScrollOnTextChangedProperty, value);
        }

        private class TextBoxScrollingTrigger : IDisposable
        {
            private TextBox TextBox { get; set; }

            public TextBoxScrollingTrigger(TextBox textBox)
            {
                TextBox = textBox;
                TextBox.TextChanged += OnTextBoxTextChanged;
            }

            private void OnTextBoxTextChanged(object sender, TextChangedEventArgs args)
            {
                TextBox.ScrollToEnd();
            }

            public void Dispose()
            {
                TextBox.TextChanged -= OnTextBoxTextChanged;
            }
        }

    }
}

Note: The textBoxesDictionary is for when there are more than one TextBox using this attached property, if we are only using one we can modify this code accordingly...

 Then we simply use it like this in XAML:
<TextBox ref:TextBoxAutomaticScrollingExtension.ScrollOnTextChanged="True" VerticalScrollBarVisibility="Auto" />

This solution is from this thread:
http://stackoverflow.com/questions/10097417/how-do-i-create-an-autoscrolling-textbox

Inga kommentarer:

Skicka en kommentar