WPF中封装DependencyProperties到DependencyObject后属性变更能否转发到UserControl
问题1解答:不会自动转发
你给外层Arrow依赖属性加的AffectsMeasure标记,只会在Arrow属性本身的值发生变更(也就是替换了整个MyArrowProperties对象实例)的时候才会触发重测。你修改Arrow.StrokeThickness属于内部子属性变更,外层依赖属性感知不到,不会触发MeasureOverride。
解决方法
推荐两种常用实现方案,你可以根据场景选择:
方案1:继承Freezable(最符合WPF原生设计,代码改动最小)
WPF的Freezable类型原生支持子属性变更通知,当它作为依赖属性的值时,内部属性变更会自动向外层所属的FrameworkElement发送通知,触发对应标记的重测/重绘逻辑。
你只需要把你的属性类从DependencyObject改成继承Freezable,实现必要的抽象方法即可:
internal class MyArrowProperties : Freezable { // 实现Freezable要求的抽象方法 protected override Freezable CreateInstanceCore() { return new MyArrowProperties(); } // 原有依赖属性注册代码不需要改动,你之前加的AffectsMeasure标记会自动生效 private static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( "StrokeThickness", typeof(double), typeof(MyArrowProperties), new FrameworkPropertyMetadata(2d, FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateStrokeThickness); // 其他属性保持不变 }
改完之后你修改Arrow.StrokeThickness就会自动触发外层ProjectListTreePanel的MeasureOverride,不需要额外写事件监听代码。
方案2:手动实现事件监听
如果你因为其他逻辑不能继承Freezable,可以自己实现属性变更通知转发:
- 首先给
MyArrowProperties添加属性变更事件:
internal class MyArrowProperties : DependencyObject { // 定义向外通知的属性变更事件 public event EventHandler SubPropertyChanged; private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var instance = (MyArrowProperties)d; instance.SubPropertyChanged?.Invoke(instance, EventArgs.Empty); } // 原有属性注册逻辑不变 private static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( "StrokeThickness", typeof(double), typeof(MyArrowProperties), new FrameworkPropertyMetadata(2d, PropertyChangedCallback), ValidateStrokeThickness); }
- 在外层
UserControl的Arrow属性变更回调中,订阅/取消订阅子属性变更事件,收到通知后主动触发重测:
public partial class ProjectListTreePanel : UserControl { private static readonly DependencyProperty ArrowProperty = DependencyProperty.Register( "Arrow", typeof(MyArrowProperties), typeof(ProjectListTreePanel), new FrameworkPropertyMetadata(null, ArrowPropertyChangedCallback)); private static void ArrowPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var panel = (ProjectListTreePanel)d; // 取消旧实例的事件订阅,避免内存泄漏 if (e.OldValue is MyArrowProperties oldProp) { oldProp.SubPropertyChanged -= panel.OnArrowSubPropertyChanged; } // 订阅新实例的事件 if (e.NewValue is MyArrowProperties newProp) { newProp.SubPropertyChanged += panel.OnArrowSubPropertyChanged; } } private void OnArrowSubPropertyChanged(object sender, EventArgs e) { // 手动触发重测 InvalidateMeasure(); } }
内容的提问来源于stack exchange,提问作者AxD
相关产品推荐
相关产品推荐

