I have a WPF application that contains a multiline TextBox that is being used to display debugging text output.
How can I set the TextBox so that as text is appended to
The answer provided by @BojinLi works well. After reading through the answer linked to by @GazTheDestroyer however, I decided to implement my own version for the TextBox, because it looked cleaner.
To summarize, you can extend the behavior of the TextBox control by using an attached property. (Called ScrollOnTextChanged)
Using it is simple:
Here is the TextBoxBehaviour class:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace MyNamespace
{
public class TextBoxBehaviour
{
static readonly Dictionary _associations = new Dictionary();
public static bool GetScrollOnTextChanged(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(ScrollOnTextChangedProperty);
}
public static void SetScrollOnTextChanged(DependencyObject dependencyObject, bool value)
{
dependencyObject.SetValue(ScrollOnTextChangedProperty, value);
}
public static readonly DependencyProperty ScrollOnTextChangedProperty =
DependencyProperty.RegisterAttached("ScrollOnTextChanged", typeof (bool), typeof (TextBoxBehaviour), new UIPropertyMetadata(false, OnScrollOnTextChanged));
static void OnScrollOnTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var textBox = dependencyObject as TextBox;
if (textBox == null)
{
return;
}
bool oldValue = (bool) e.OldValue, newValue = (bool) e.NewValue;
if (newValue == oldValue)
{
return;
}
if (newValue)
{
textBox.Loaded += TextBoxLoaded;
textBox.Unloaded += TextBoxUnloaded;
}
else
{
textBox.Loaded -= TextBoxLoaded;
textBox.Unloaded -= TextBoxUnloaded;
if (_associations.ContainsKey(textBox))
{
_associations[textBox].Dispose();
}
}
}
static void TextBoxUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
var textBox = (TextBox) sender;
_associations[textBox].Dispose();
textBox.Unloaded -= TextBoxUnloaded;
}
static void TextBoxLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var textBox = (TextBox) sender;
textBox.Loaded -= TextBoxLoaded;
_associations[textBox] = new Capture(textBox);
}
class Capture : IDisposable
{
private TextBox TextBox { get; set; }
public Capture(TextBox textBox)
{
TextBox = textBox;
TextBox.TextChanged += OnTextBoxOnTextChanged;
}
private void OnTextBoxOnTextChanged(object sender, TextChangedEventArgs args)
{
TextBox.ScrollToEnd();
}
public void Dispose()
{
TextBox.TextChanged -= OnTextBoxOnTextChanged;
}
}
}
}