WPF自定义控件响应依赖属性变更的正确实现方式咨询
现有实现的问题
if(e.Property.Name == nameof(ChannelsYSpacing))判断完全冗余:这个回调是你注册ChannelsYSpacingProperty时专属绑定的,只有该依赖属性发生变更时才会触发,永远不会出现其他属性进入这个回调的情况,直接删除该判断即可。- 回调中主动给
ChannelsYSpacing赋值的逻辑是多余且不符合WPF设计规范的:WPF的依赖属性系统在触发PropertyChangedCallback时,已经完成了属性值的更新,你不需要手动再赋值一次。而且WPF通过绑定、样式、动画等方式更新依赖属性时,不会走CLR属性包装器的setter,你现在的逻辑能跑通本质是靠回调手动触发setter,属于非常规实现,还存在触发重复赋值、无限递归的风险。 - 你的ViewModel代码里存在笔误:
YSpacing的setter中loginViewModel = value;明显是写错了,应该改为ySpacing = value;,否则属性赋值会失效。
最优实现方案
你只需要调整依赖属性相关的代码,完全不需要靠回调触发CLR setter,把重绘逻辑统一放到变更回调里即可:
/// <summary> /// Y-Distance between each band of data /// </summary> [Category("Common")] public int ChannelsYSpacing { get => (int)GetValue(ChannelsYSpacingProperty); set => SetValue(ChannelsYSpacingProperty, value); } public static readonly DependencyProperty ChannelsYSpacingProperty = DependencyProperty.Register( nameof(ChannelsYSpacing), typeof(int), typeof(ChannelsDisplay), new FrameworkPropertyMetadata(20, OnSpacingChanged)); private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var channelsDisplay = (ChannelsDisplay)d; // 直接在回调里执行重绘逻辑即可,所有属性变更(包括绑定、手动赋值)都会触发这个回调 channelsDisplay.createScaledLines(); channelsDisplay.createVisibleLines(); channelsDisplay.updateCanvas(); }
这个实现的优势:
- 没有冗余判断、没有重复赋值,完全符合WPF依赖属性的设计规范
- 不管是通过绑定更新属性,还是手动在代码里给
ChannelsYSpacing赋值,都会统一触发重绘逻辑,不会出现漏更新的情况 - 性能更优,省去了不必要的二次SetValue调用
内容的提问来源于stack exchange,提问作者phibel
相关产品推荐
相关产品推荐

