DependencyProperty 和 DataBinding - 为什么加载 UserControl 时不调用 属性 setter?

DependencyProperty and DataBinding - Why property setter isn't called when UserControl loads?

我想为 RangeSlider 的行为建模,使用 class RangeSliderModel 以及描述一组给定值的大小(宽度)的属性。

然后,我创建了一个 UserControl,其中一些矩形的位置和大小应该表示这些属性,以及 Thumb 的一些实例,DragDelta 事件用于调整这些矩形的大小并启用RangeSliderModel.

的新值的计算

最后,这个 UserControl 有一个 DependencyProperty 类型 RangeSliderModel:

    public RangeSliderModel Model
    {
        get
        {
            return (RangeSliderModel)GetValue(RangeSliderModelProperty);
            // or instead calculate a RangeSliderModel from children sizes.
        }
        set
        {
            // this IS NOT called when UserControl loads
            SetValue(RangeSliderModelProperty, value);
            // here I could take the value and calculate new sizes for the children.
        }
    }

    public static readonly DependencyProperty RangeSliderModelProperty =
        DependencyProperty.Register("RangeSliderModel",
                                    typeof(RangeSliderModel),
                                    typeof(MyUserControl),
                                    new PropertyMetadata(ModelPropertyChanged));

    private static void ModelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // this IS called when UserControl loads.
        RangeSliderModel model = e.NewValue as RangeSliderModel;
    }

我期望覆盖 SetValueGetValue 属性,但即使我将此 DependencyProperty 绑定到 ViewModel 中的相应源,也永远不会调用 setter!而且我不太明白为什么 PropertyChangedHandler 被调用,更不用说我应该如何处理这些信息了——我期望以类似于 ValueConverter 的方式只使用 GetValueSetValue

当您通过绑定设置依赖属性时,它们不会以这种方式工作。 DependencyObject.SetCurrentValue调用。绑定正在调用(本质上):

yourObject.SetCurrentValue(YourClassName.RangeSliderModelProperty, someValue);

所以,是的,SetCurrentValue vs SetValueSetValue 将覆盖依赖项 属性 上的任何绑定; SetCurrentValue 不会。 IIRC 这与 XAML 中的样式触发器无法覆盖属性设置的值的方式有关。幸运的是,它与您在这里所做的事情没有直接关系。

最重要的是,您的 ModelPropertyChanged 处理程序是放置值更改时需要调用的代码的地方。依赖属性和常规 .NET CLR 属性是两个独立的机制。

如果我完全省略了 public 属性,我已经在 XAML 中正确绑定了依赖属性;我刚刚再次测试,发现我的测试示例就是这种情况。在评论中你提到你没有发现你的代码是这种情况,所以很明显我需要做更多的阅读。

如果您需要让子类响应更改,您可以编写一个它们可以覆盖的虚方法,并在 ModelPropertyChanged 中调用它,或者编写一个 ModelChanged 事件并在ModelPropertyChanged

他们 可以 通过 DependencyPropertyDescriptor 添加一个 ValueChanged 处理程序,但是你最好让他们免去谷歌搜索的麻烦为此,通过编写虚拟方法或事件。