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

时间:2015-02-03 14:50:06

标签: c# wpf xaml dependency-properties

当我在运行时设置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未被Designer修改,只有IsClosedProperty才会收到xaml更改。
我的问题是:如何在Designer中修改值后运行IsClosed。或者至少为非运行时更改添加一些逻辑。

2 个答案:

答案 0 :(得分:8)

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

原因是在XAML中设置的依赖项属性或绑定或某些其他源不会调用CLR包装器(setter方法)。原因在MSDN上的XAML Loading and Dependency Properties文章中进行了解释:

  

出于实施原因,它在计算上更便宜   将属性标识为依赖属性并访问该属性   系统SetValue方法设置它,而不是使用属性   包装器和它的二传手。

     

...

     

因为当前的WPF实现了XAML处理器的行为   对于属性设置完全绕过包装器,你不应该   将任何其他逻辑放入包装器的set定义中   您的自定义依赖属性。如果你把这样的逻辑放在集合中   定义,然后在属性时不执行逻辑   在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 :(得分: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的{​​{1}} 感谢您的帮助!