何时使用依赖属性

14

我有时候觉得我可能不必要使用依赖属性。那么什么时候需要使用它呢?当我有一个依赖其他属性的属性时?比如,我有一个Color属性,我希望它依赖于Hue、Saturation和Luminosity属性,我应该使用依赖属性吗?还是其他什么东西?当Hue、Saturation和Luminosity属性发生变化时,我的控件绑定到Color需要更新。

目前为止,我所做的是:

public byte Hue {
    get { return _hue; }
    set
    {
        if (_hue == value)
            return;
        _hue = value;
        NotifyPropertyChanged("Hue");
        NotifyPropertyChanged("Color"); // to update controls bound to color
    }
}

但我认为这不是做事情的正确方式?如果我有更多影响颜色的属性,那么所有这些属性都会多出1行吗?


1
我认为这并不是代码方面不合理的开销,而且肯定比添加一个DependencyProperty更轻量级。 - Dan Puzey
如果你要使用HSL颜色方案,我建议你这样做,这样就不需要频繁计算。例如,始终存储H、S和L,并且只在需要同步时进行转换。这将极大地提高你的速度。 - Lee Louviere
6个回答

21

只有在想通过 XAML 绑定某个值时,才应该使用 DependencyProperty

<local:MyObject MyDependencyProperty="{Binding ...}" />

更新:如Ian在下面所述,如果要对属性进行动画或通过样式设置属性,则还需要依赖属性。

如果您不需要以这种方式工作,则这是不必要的。例如,如果您只想通过XAML将值设置为常量(如下所示),则可以不使用DependencyProperty来实现。

<local:MyObject MyRegularProperty="Some Value" />

同样地,如果你想要绑定 (例如) 你的视图模型上某个属性的值:

<TextBlock Text="{Binding MyViewModelProperty}" />

如果你实现了INotifyPropertyChanged接口,那么就不需要使用DependencyProperty。当属性变化时,Text仍然会更新。

编辑:再次阅读您的问题后,我不确定您是否使用DependencyProperty会受到影响 - 如果我理解正确,您只想在这些属性中的任何一个发生更改时引起UI上多个属性的更新,是吗?

我认为您目前的实现方式没有任何问题(即在每个setter中引发大量的PropertyChanged事件),但如果您不喜欢它,可以尝试使用一个单独的属性,该属性公开相关的子属性来绑定,这些属性都是计算得出的:

class ColorWrapper
{
    public Color Color  { get; set; }
    public byte Hue
    {
        get { return this.Color.Hue; } //or however this is calculated
}

在您的ViewModel上拥有一个Color属性,该属性引发PropertyChanged事件,并通过View对其进行绑定:

<TextBlock Text="{Binding Color.Hue}" />

就像我说的那样,我不认为这比你已经拥有的东西更好。


绑定不是唯一的用例。如果实现属性的对象是UI元素(有些人在非UI对象上实现DP),则DP系统可以启用各种其他功能,包括动画、样式和(仅限WPF - Silverlight没有这些)触发器。此外,如果属性经常保留其默认值,则DP非常有用,因为每个实例仅使用已设置的DP的空间。 - Ian Griffiths
@Ian Griffiths,关于动画和样式的观点很好 - 回答已更新。你对默认值的评论也是有道理的,但考虑到实现和使用依赖属性相比普通属性所涉及的开销(特别是如果你还没有在一个“DependencyObject”上工作),我通常不会选择这条路。 - Steve Greatrex
4
默认值对WPF性能有着不可忽视的影响。它可以每个对象节省几百字节,如果您的可视树包含几千个对象,那么就是几百KB。这在整体内存中只是很小的一部分,但足以对CPU高效缓存的使用产生巨大影响(尤其是在布局期间)。然而,默认值对任何非UI对象都可能不相关,而对于自定义UI元素可能也没有太大帮助,在这种情况下,您很可能会设置您定义的任何自定义属性。所以我同意......我只是想说明DP有几个用途。 - Ian Griffiths
有趣的是,我之前没有考虑过性能方面的问题 :) - Steve Greatrex

15

一般规则如下:

  • 对于 XAML 控件,请使用依赖属性 (dependency properties);

  • 对于数据(在界面中绑定的数据),请使用 INotifyPropertyChanged

当然也有例外情况,但它们很少见。


2

依赖属性的另一个用途是与导航日志一起使用。在元数据中带有Journal标志的页面上的自定义依赖属性包含在WPF为该页面保存的状态中。


0

请记住,依赖属性虽然允许绑定作为源或目标,但也是线程敏感的。在序列化时,您将需要使用代理,因为将DependencyObject序列化不可行。

哦,还有Equals和GetHashCode是密封的:(


0

我经常陷入 DependencyProperty 的“陷阱”。

在某个时候,我意识到每一个值的任何变化都会以某种方式和某个地方触发,可以是算法、进程、用户输入...等等很多东西,但它永远不会自己改变。

掌握这些触发器,直接在源头挂钩,你就不需要 DependencyProperty,甚至不需要 INotifyPropertyChanged。我的意思是,也许我做错了或者做对了,但所有的问题,它们有时候非常困难,我只用 RoutedEvents 和 Properties { get , set } 就解决了。在 get、set 中,你可以做很多事情。不能在这里解决的所有问题,都可以用 AddHandler 解决,不再需要时别忘了 RemoveHandler。 同时,还需要扎实的线程和调度知识。 同时,还需要良好的 Lambda 表达式和 Actions 使用技巧。 (可能不适用于 Windows Phone 等应用程序,仅供参考)

分别是:一个严重的缺点是编码控制和努力。对于这个方法,我需要编写更多代码并具有更好的文档,最大的优势是更好地理解应用程序中实际发生的情况以及可能发生的情况以及其范围。在性能方面没有任何缺点,甚至更快,因为当您直接连接到触发器时,您正在使用最轻便和最适合的方法-仅在必要时执行代码,并且只有所需的那么重。

最后:DependencyProperties可能在非常敏感的应用程序中有意义,在这些应用程序中,您实际上不知道可能的关系和反应。这可能超过一百万种可能的情况->您不想对这些情况进行控制,否则您永远无法完成产品。 注意事项:并非所有看起来像产生大量未知情况的东西都是未知的。您可以使用范围(从x到y)并编写算法,以一种方法重新控制数千种可能的情况。

所以这就是我的两分钱:在大多数情况下,DependencyProperties和INotifyPropertyChanged并不需要,只是为了在理解产品和(有时)性能的代价下获得更轻松的编码生活。

(提醒自己:我写下这段话是因为我刚刚遇到了一个情况,我认为我需要 DependencyProperty,这次是真的需要了...但是没有...思考了一个小时,解决方案很简单,找到了触发器。)

0
DP 的另一个用途是附加属性。附加属性是 DependencyProperty 的一种,其中该属性可以在任何其他控件中使用。 例如,您可以在 MyAttachedProperties 类中声明 AttachedProperty,并将其用于 TextBlock、Button、Label 等控件。
一些附加属性的示例包括 Grid.Row、Grid.Column。还有一些自定义的附加属性:
public static readonly DependencyProperty DarkThemeProperty =
    DependencyProperty.RegisterAttached("DarkTheme", typeof(Theme), typeof(Page));
 
public static Theme GetDarkTheme(DependencyObject obj)
{
    return (Theme)obj.GetValue(DarkThemeProperty);
}
 
public static void SetDarkTheme(DependencyObject obj, Theme value)
{
    obj.SetValue(DarkThemeProperty, value);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接