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;
}
我期望覆盖 SetValue
和 GetValue
属性,但即使我将此 DependencyProperty 绑定到 ViewModel 中的相应源,也永远不会调用 setter!而且我不太明白为什么 PropertyChangedHandler 被调用,更不用说我应该如何处理这些信息了——我期望以类似于 ValueConverter 的方式只使用 GetValue
和 SetValue
。
当您通过绑定设置依赖属性时,它们不会以这种方式工作。 DependencyObject.SetCurrentValue
被调用。绑定正在调用(本质上):
yourObject.SetCurrentValue(YourClassName.RangeSliderModelProperty, someValue);
所以,是的,SetCurrentValue vs SetValue。 SetValue
将覆盖依赖项 属性 上的任何绑定; SetCurrentValue
不会。 IIRC 这与 XAML 中的样式触发器无法覆盖属性设置的值的方式有关。幸运的是,它与您在这里所做的事情没有直接关系。
最重要的是,您的 ModelPropertyChanged
处理程序是放置值更改时需要调用的代码的地方。依赖属性和常规 .NET CLR 属性是两个独立的机制。
如果我完全省略了 public 属性,我已经在 XAML 中正确绑定了依赖属性;我刚刚再次测试,发现我的测试示例就是这种情况。在评论中你提到你没有发现你的代码是这种情况,所以很明显我需要做更多的阅读。
如果您需要让子类响应更改,您可以编写一个它们可以覆盖的虚方法,并在 ModelPropertyChanged
中调用它,或者编写一个 ModelChanged
事件并在ModelPropertyChanged
。
他们 可以 通过 DependencyPropertyDescriptor
添加一个 ValueChanged
处理程序,但是你最好让他们免去谷歌搜索的麻烦为此,通过编写虚拟方法或事件。
我想为 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;
}
我期望覆盖 SetValue
和 GetValue
属性,但即使我将此 DependencyProperty 绑定到 ViewModel 中的相应源,也永远不会调用 setter!而且我不太明白为什么 PropertyChangedHandler 被调用,更不用说我应该如何处理这些信息了——我期望以类似于 ValueConverter 的方式只使用 GetValue
和 SetValue
。
当您通过绑定设置依赖属性时,它们不会以这种方式工作。 DependencyObject.SetCurrentValue
被调用。绑定正在调用(本质上):
yourObject.SetCurrentValue(YourClassName.RangeSliderModelProperty, someValue);
所以,是的,SetCurrentValue vs SetValue。 SetValue
将覆盖依赖项 属性 上的任何绑定; SetCurrentValue
不会。 IIRC 这与 XAML 中的样式触发器无法覆盖属性设置的值的方式有关。幸运的是,它与您在这里所做的事情没有直接关系。
最重要的是,您的 ModelPropertyChanged
处理程序是放置值更改时需要调用的代码的地方。依赖属性和常规 .NET CLR 属性是两个独立的机制。
如果我完全省略了 public 属性,我已经在 XAML 中正确绑定了依赖属性;我刚刚再次测试,发现我的测试示例就是这种情况。在评论中你提到你没有发现你的代码是这种情况,所以很明显我需要做更多的阅读。
如果您需要让子类响应更改,您可以编写一个它们可以覆盖的虚方法,并在 ModelPropertyChanged
中调用它,或者编写一个 ModelChanged
事件并在ModelPropertyChanged
。
他们 可以 通过 DependencyPropertyDescriptor
添加一个 ValueChanged
处理程序,但是你最好让他们免去谷歌搜索的麻烦为此,通过编写虚拟方法或事件。