WPF Extended Textbox Override not working correctly

88 Views Asked by At

I have created a CustomTextBox which extends TextBox.

I have overridden the Metadata for TextProperty because I want to trigger a method when the text changes, but when I run my code and edit the textbox, I am only seeing the OnTextPropertyChanged event fired twice. First time when I initialise the textbox, and the second when I close the window.

How can I have this fired for each keystroke in the Textbox?

AppTextBox.cs:

public class AppTextBox : TextBox
{
    static AppTextBox()
    {
        TextProperty.OverrideMetadata(typeof(AppTextBox),
                                      new FrameworkPropertyMetadata(
                                          string.Empty,
                                          FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                                          OnTextPropertyChanged,
                                          null,
                                          true,
                                          UpdateSourceTrigger.PropertyChanged)
                                      );

        DefaultStyleKeyProperty.OverrideMetadata(typeof(AppTextBox), new FrameworkPropertyMetadata(typeof(AppTextBox)));
    }

    private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
       // TODO: Check if Text is null or empty...
    }
}

Usage:

<ctrl:AppTextBox Text="{Binding NewWord.WrittenForm}" />

So when I first load the textbox, the content is "Foo".

When I add or delete a letter, I would expect the OnTextPropertyChanged to be fired, but it is not. Should I be doing something different to achieve my goal?

1

There are 1 best solutions below

8
MIHOW On BEST ANSWER

This propdp can be simplified.

public partial class AppTextBox : TextBox
{
    public static new readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(AppTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnTextPropertyChanged)));
    public new string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
    private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine("OnTextPropertyChanged");
    }

    public AppTextBox()
    {
        InitializeComponent();
    }
}

The trick is to provide binding on the derived control

x:Name="self"
Text="{Binding ElementName=self, Path=Text, UpdateSourceTrigger=PropertyChanged}"

and here's the full control

<TextBox x:Class="WpfApp10.AppTextBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:local="clr-namespace:WpfApp10"
         x:Name="self"
         Text="{Binding ElementName=self, Path=Text, UpdateSourceTrigger=PropertyChanged}"
         mc:Ignorable="d"
         d:DesignWidth="800"
         d:DesignHeight="450"/>