WPF自定义TextBox重写TextProperty元数据未按预期触发变更事件
自定义TextBox控件TextProperty变更事件不触发的解决方法
我创建了一个继承自TextBox的自定义控件AppTextBox,重写了TextProperty的元数据,期望文本变更时触发OnTextPropertyChanged方法。但运行后发现,该事件仅在控件初始化和窗口关闭时各触发一次,输入字符时并未触发。如何实现每一次按键操作都触发该事件?
现有代码
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... } }
使用示例
<ctrl:AppTextBox Text="{Binding NewWord.WrittenForm}" />
控件初始加载时内容为"Foo",但添加或删除字符时,预期触发的OnTextPropertyChanged事件并未执行。
问题原因
WPF的TextBox内部对Text依赖属性的更新做了延迟处理:输入文本时,控件会先维护内部的编辑缓冲区,仅在失去焦点、按下回车等特定时机才会将缓冲区内容同步到Text依赖属性。因此即使你在元数据中设置了UpdateSourceTrigger.PropertyChanged,也无法让PropertyChanged回调在每次按键时触发。
解决方法
方法1:重写OnTextChanged虚方法(推荐)
TextBox提供了受保护的OnTextChanged虚方法,每次文本内容变更(按键、粘贴、删除等)都会触发,重写该方法即可捕获每次文本变更:
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... } protected override void OnTextChanged(TextChangedEventArgs e) { base.OnTextChanged(e); // 获取文本变更前后的值 string oldText = e.OldText?.ToString() ?? string.Empty; string newText = Text; // 手动触发PropertyChanged回调 OnTextPropertyChanged(this, new DependencyPropertyChangedEventArgs(TextProperty, oldText, newText)); } }
方法2:监听TextChanged事件
在控件构造函数中绑定TextChanged事件,在事件处理逻辑中执行你的业务代码:
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))); } public AppTextBox() { TextChanged += AppTextBox_TextChanged; } private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // TODO: Check if Text is null or empty... } private void AppTextBox_TextChanged(object sender, TextChangedEventArgs e) { string oldText = e.OldText?.ToString() ?? string.Empty; string newText = Text; OnTextPropertyChanged(this, new DependencyPropertyChangedEventArgs(TextProperty, oldText, newText)); } }
内容的提问来源于stack exchange,提问作者Richard Gale
相关产品推荐
相关产品推荐

