如何为已有Text属性绑定自动设置NotifyOnTargetUpdated以支持附加行为
问题根源说明
- 初始获取
textBinding为null是因为附加属性的回调触发时机早于Text属性绑定的应用时机,样式Setter的执行顺序和XAML属性赋值顺序会导致这个问题 - 绑定使用后不可修改是WPF的设计限制,已经关联到依赖属性的Binding实例是密封的,不能修改其属性
方案1:直接监听Text属性变更(推荐,无侵入)
不需要修改原有绑定,通过DependencyPropertyDescriptor直接监听Text属性的值变化,完全不需要依赖NotifyOnTargetUpdated配置。
// 附加属性变更回调 private static void OnAutoSizeTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var tb = d as TextBlock; if (tb == null) return; if ((bool)e.NewValue) { // 等待元素加载完成,确保所有属性已应用 tb.Loaded += (sender, args) => { var textPropDesc = DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock)); // 注册Text属性变更回调 textPropDesc.AddValueChanged(tb, OnTextBlockTextChanged); // 首次加载主动触发一次处理逻辑 OnTextBlockTextChanged(tb, EventArgs.Empty); }; // 元素卸载时清理监听,避免内存泄漏 tb.Unloaded += (sender, args) => { var textPropDesc = DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock)); textPropDesc.RemoveValueChanged(tb, OnTextBlockTextChanged); }; } else { // 附加属性关闭时清理监听 var textPropDesc = DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock)); textPropDesc.RemoveValueChanged(tb, OnTextBlockTextChanged); } } // Text属性变更处理逻辑 private static void OnTextBlockTextChanged(object sender, EventArgs e) { var tb = sender as TextBlock; if (tb == null) return; // 这里写你要处理的文本变更后的逻辑 }
该方案不需要修改原有绑定,也不依赖XAML编写顺序,适配所有绑定和静态赋值的Text场景。
方案2:克隆原有绑定并修改配置
如果你的逻辑确实需要依赖TargetUpdated事件,可以在元素加载完成后,克隆原有绑定实例,修改配置后重新应用:
private static void OnAutoSizeTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var tb = d as TextBlock; if (tb == null) return; if ((bool)e.NewValue) { tb.Loaded += (sender, args) => { var originalBinding = BindingOperations.GetBinding(tb, TextBlock.TextProperty); if (originalBinding == null) return; // 克隆原有绑定的所有配置 var newBinding = new Binding { Path = originalBinding.Path, Mode = originalBinding.Mode, UpdateSourceTrigger = originalBinding.UpdateSourceTrigger, Converter = originalBinding.Converter, ConverterParameter = originalBinding.ConverterParameter, ConverterCulture = originalBinding.ConverterCulture, Source = originalBinding.Source, RelativeSource = originalBinding.RelativeSource, ElementName = originalBinding.ElementName, FallbackValue = originalBinding.FallbackValue, TargetNullValue = originalBinding.TargetNullValue, StringFormat = originalBinding.StringFormat, NotifyOnTargetUpdated = true }; // 清除旧绑定,应用新绑定 BindingOperations.ClearBinding(tb, TextBlock.TextProperty); tb.SetBinding(TextBlock.TextProperty, newBinding); // 订阅TargetUpdated事件 tb.TargetUpdated += OnTextTargetUpdated; }; tb.Unloaded += (sender, args) => { tb.TargetUpdated -= OnTextTargetUpdated; }; } } private static void OnTextTargetUpdated(object sender, DataTransferEventArgs e) { if (e.Property == TextBlock.TextProperty) { // 处理文本变更逻辑 } }
注意该方案需要完整复制原绑定的所有配置属性,避免丢失原有绑定的逻辑。
内容的提问来源于stack exchange,提问作者Travis
相关产品推荐
相关产品推荐

