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

Callback when dependency property receives xaml change

提问人:Noel Widmer 提问时间:2/3/2015 最后编辑:ClemensNoel Widmer 更新时间:11/4/2023 访问量:4230

问:

当我在运行时设置值时,称为fine。 但是,设计器设置属性的值,但不调用 .IsClosedOnIsClosedChanged()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);
}

显然,设计器不会对其进行修改,而只会接收 xaml 更改。
我的问题是:在设计器中修改值后如何运行。或者至少为非运行时更改添加一些逻辑。
IsClosedIsClosedPropertyIsClosed

C# WPF XAML 依赖项属性

评论

2赞 Alex K. 2/3/2015
您是否尝试过使用 ValidateValueCallback?使用 DependencyProperty.Register msdn.microsoft.com/en-us/library/ms597501(v=vs.110) 的重载方法.aspx
0赞 Sinatr 2/3/2015
我前段时间也犯了同样的错误。依赖属性是深层的东西。该属性仅为你公开它,但 WPF 不使用你的属性(你可以删除它)。@AlexK,注释是正确的(可能是答案),当依赖属性(不要与您的属性混淆)被 UI(由设计器、运行时用户等)更改时,使用回调来获得通知。

答:

1赞 Noel Widmer 2/3/2015 #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);
        }

现在确实重新设置了触发运行的 。
谢谢你们的帮助!
IsClosedValueOnIsClosedChanged

评论

0赞 Alex K. 2/3/2015
右。我的意思是 PropertyChangedCallback 当然 =)
2赞 Clemens 2/3/2015
最后一步:从属性 setter 方法中删除。并且不要在 PropertyChangedCallback 中再次设置该属性。这没有意义。OnIsClosedChanged()
13赞 Clemens 2/3/2015 #2

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

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

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

...

由于当前 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);
}

评论

0赞 Noel Widmer 2/3/2015
克莱门斯又一次!几分钟前自己找到了答案。但参考很有趣......谢谢:)