wpftextboxoverridingmetadatacustom-controls

WPF Extended Textbox Override not working correctly


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?


Solution

  • 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"/>