依赖属性收到 xaml 更改时的回调

Posted

技术标签:

【中文标题】依赖属性收到 xaml 更改时的回调【英文标题】:Callback when dependency property recieves xaml change 【发布时间】:2015-04-02 19:38:21 【问题描述】:

当我在运行时设置IsClosed 的值时,OnIsClosedChanged() 调用正常。 但是,Designer 设置属性的值但不调用OnIsClosedChanged()

public static DependencyProperty IsClosedProperty = DependencyProperty.Register("IsClosed", typeof(bool), typeof(GroupBox), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));

public bool IsClosed 
    get 
        return (bool)this.GetValue(IsClosedProperty);
    
    set 
        if ((bool)this.GetValue(IsClosedProperty) == value)
            return;

        this.SetValue(IsClosedProperty, value);
        OnIsClosedChanged();
    




private void OnIsClosedChanged() 
    _rowDefContent.Height = new GridLength((IsClosed ? 0 : 1), GridUnitType.Star);

显然IsClosed 未被设计器修改,只有IsClosedProperty 接收xaml 更改。 我的问题是:在 Designer 中修改值后,如何运行 IsClosed。或者至少为非运行时更改添加一些逻辑。

【问题讨论】:

您是否尝试过使用 ValidateValueCallback?使用 DependencyProperty.Register msdn.microsoft.com/en-us/library/ms597501(v=vs.110).aspx 的重载方法 我前段时间犯了同样的错误。依赖属性是很深的东西。该属性仅为您公开它,但 WPF 不使用您的属性(您可以将其删除)。而@AlexK,评论是正确的(它可能是答案),当 UI 更改 dependency property(不要误认为 your property)时,使用回调来获得通知(由设计者、运行时的用户等)。 【参考方案1】:

您必须使用属性元数据注册 PropertyChangedCallback。

原因是在 XAML 中或通过绑定或其他一些源设置的依赖属性不会调用 CLR 包装器(setter 方法)。原因在 MSDN 上的XAML Loading and Dependency Properties 文章中有说明:

出于实现原因,计算成本更低 将属性标识为依赖属性并访问该属性 系统 SetValue 方法来设置它,而不是使用属性 包装器及其设置器。

...

因为 XAML 处理器行为的当前 WPF 实现 对于属性设置完全绕过包装,你不应该 将任何附加逻辑放入包装器的集合定义中 您的自定义依赖项属性。如果你把这样的逻辑放在集合中 定义,那么当属性为 在 XAML 中而不是在代码中设置。

您的代码应如下所示:

public static readonly DependencyProperty IsClosedProperty =
    DependencyProperty.Register(
        "IsClosed", typeof(bool), typeof(GroupBox),
        new FrameworkPropertyMetadata(false,
            FrameworkPropertyMetadataOptions.AffectsRender,
            (o, e) => ((GroupBox)o).OnIsClosedChanged()));

public bool IsClosed

    get  return (bool)GetValue(IsClosedProperty); 
    set  SetValue(IsClosedProperty, value); 


private void OnIsClosedChanged()

    _rowDefContent.Height = new GridLength((IsClosed ? 0 : 1), GridUnitType.Star);

【讨论】:

克莱门斯又一次!几分钟前自己找到了答案。但是这个参考很有趣……谢谢:)【参考方案2】:

现在自己找到了答案。 ValidateValueCallback 非常接近! (正如 Alex K 指出的那样)但它是一种静态方法,我没有得到任何对已更改实例的引用。关键是在 FrameworkPropertyMetadata 中使用 PropertyChangedCallback,它也是传递给 Property.Register 方法的参数。 请参阅:

public static DependencyProperty IsClosedProperty = DependencyProperty.Register("IsClosed", typeof(bool), typeof(GroupBox), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnIsClosedChangedPCC)));

        public bool IsClosed 
            get 
                return (bool)this.GetValue(IsClosedProperty);
            
            set 
                this.SetValue(IsClosedProperty, value);
                OnIsClosedChanged();
            
        



        private static void OnIsClosedChangedPCC(DependencyObject d, DependencyPropertyChangedEventArgs e) 
            GroupBox current = (GroupBox)d;
            current.IsClosed = current.IsClosed;
        



        private void OnIsClosedChanged() 
            _rowDefContent.Height = new GridLength((IsClosed ? 0 : 1), GridUnitType.Star);
        

现在确实重新设置了IsClosedValue,这会触发OnIsClosedChanged 运行。 谢谢你们的帮助!

【讨论】:

对。我的意思当然是 PropertyChangedCallback =) 最后一步:从你的属性设置方法中删除OnIsClosedChanged()。并且在 PropertyChangedCallback 中不要再次设置属性。这没有意义。

以上是关于依赖属性收到 xaml 更改时的回调的主要内容,如果未能解决你的问题,请参考以下文章

将 GeometryDrawing 画笔绑定到自定义控件依赖属性

Wpf:通用集合依赖属性

如何在XAML中动态更改运行时的PATH DATA属性?

WPF xaml中列表依赖属性的定义

WPF枚举标志XAML属性编辑器中的依赖属性

WPF 让普通 CLR 属性支持 XAML 绑定(非依赖属性),这样 MarkupExtension 中定义的属性也能使用绑定了