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

问题描述 投票:0回答:2

当我在运行时设置

IsClosed
的值时,
OnIsClosedChanged()
被称为fine。 然而,设计者设置属性的值但不调用
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 更改。
我的问题是:在设计器中修改值后如何运行
IsClosed
。或者至少为非运行时更改添加一些逻辑。

c# wpf xaml dependency-properties
2个回答
13
投票

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

原因是在 XAML 中或通过绑定或其他源设置的依赖属性不会调用 CLR 包装器(setter 方法)。 MSDN 上的XAML 加载和依赖属性文章中解释了原因:

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

...

因为当前的 WPF 实现了 XAML 处理器行为 对于属性设置完全绕过包装器,您不应该 将任何附加逻辑放入包装器的集合定义中 您的自定义依赖属性。如果你把这样的逻辑放在集合中 定义,那么当属性为时逻辑将不会被执行 在 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);
}

1
投票

现在我自己找到了答案。 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
运行。
谢谢你们的帮助!

© www.soinside.com 2019 - 2024. All rights reserved.