何时使用WPF依赖属性而不是INotifyPropertyChanged

37

大家对于何时在视图模型中使用触发 INotifyPropertyChanged.PropertyChanged 的简单 .NET 属性有什么指导意见吗?那么,何时需要升级为完整的依赖属性呢?或者说,依赖属性主要是用于视图吗?

5个回答

53

有几种方法:

1. 依赖属性

当你使用依赖属性时,它最适用于具有视觉外观的元素类(UIElement)。

优点:

  • WPF会为您处理逻辑操作
  • 某些机制例如动画仅使用依赖属性
  • “适合”ViewModel样式

缺点:

  • 您需要从DependencyObject派生出来
  • 对于简单的事情有点笨拙

示例:

public static class StoryBoardHelper
{
    public static DependencyObject GetTarget(Timeline timeline)
    {
        if (timeline == null)
            throw new ArgumentNullException("timeline");

        return timeline.GetValue(TargetProperty) as DependencyObject;
    }

    public static void SetTarget(Timeline timeline, DependencyObject value)
    {
        if (timeline == null)
            throw new ArgumentNullException("timeline");

        timeline.SetValue(TargetProperty, value);
    }

    public static readonly DependencyProperty TargetProperty =
            DependencyProperty.RegisterAttached(
                    "Target",
                    typeof(DependencyObject),
                    typeof(Timeline),
                    new PropertyMetadata(null, OnTargetPropertyChanged));

    private static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Storyboard.SetTarget(d as Timeline, e.NewValue as DependencyObject);
    }
}

2. System.ComponentModel.INotifyPropertyChanged

通常,在创建数据对象时,您将使用此方法。这是一种针对类似数据的东西的简单而整洁的解决方案。

优缺点-与1相辅相成。 您只需要实现一个事件(PropertyChanged)。

示例:

public class Student : INotifyPropertyChanged 
{ 
   public event PropertyChangedEventHandler PropertyChanged; 
   public void OnPropertyChanged(PropertyChangedEventArgs e) 
   { 
       if (PropertyChanged != null) 
          PropertyChanged(this, e); 
   } 
}

private string name; 
public string Name; 
{ 
    get { return name; } 
    set { 
           name = value; 
           OnPropertyChanged(new PropertyChangedEventArgs("Name")); 
        } 
} 

3. PropertyNameChanged

针对每个指定名称的属性(例如 NameChanged),触发一个事件。这个事件必须具有该名称,你需要处理/触发它们。类似于第2种方法。

4. 获取绑定关系

使用FrameworkElement.GetBindingExpression()可以获取BindingExpression对象, 并调用BindingExpression.UpdateTarget()进行刷新。

第一种和第二种方法最有可能取决于你的目标。

总之,它是视觉与数据之间的区别。


1
这是一个很棒的答案,值得更多的赞!如果可以的话,我会投两次票。 :-) - Keith Hill

15
据我所知,DependencyProperty 仅在以下情况下需要使用:
  1. 需要属性值继承
  2. 需要允许该属性在样式设置器中设置
  3. 需要对该属性进行动画处理

普通属性无法提供这些功能。


4

DependencyProperty 是必须的,如果您想允许在属性上设置绑定。通常这是用于您创建的自定义 UIElement。您希望允许用户能够将数据绑定到您的 UIElement

<local:MyUIElement MyProperty={Binding Path=SomethingToBindTo} />

为了实现这一点,需要将MyProperty定义为一个依赖属性。

这实际上是正确的答案。只有在您想要将属性作为绑定的目标时才需要DependencyProperty。其他情况下,如果需要,您可以使用标准属性加上INotifyPropertyChanged来完成。 - user3230660
我相当确定我已经使用了INotifyPropertyChanged很多次,你的回答中有没有任何“隐藏的方面”是不明确的? - Daniel Möller

1
我认为INotifyPropertyChanged的主要问题在于,如果您的视图模型很复杂,包含许多嵌套类型,那么似乎您必须通过层次结构向上冒泡PropertyChanged事件。

1
作为其他答案已经充分解释了何时创建依赖属性,即:
1. PropertyValue inheritence 2. 您需要在属性上使用绑定 3. 对属性使用动画
另一个角度/问题是:“在WPF应用程序中,在控件中创建依赖属性是有意义的,因为它们很可能会在用户交互期间更改,如高度、宽度、文本、内容、背景等,但是对于其他类(非UI类)如Behaviors Classes中的属性,是否需要将这些类中的属性设置为依赖属性?”
我不会说绝对或强调一些规则,但您应该将属性创建为DP。从设计角度来看,如果属性是DP,则始终处于WPF默认形式以使用/绑定。即:
1. 与普通CLR属性相比,DP更快/自然地反映更改。 2. DP具有验证机制来验证分配的值和恢复值的默认结构。 3. DP具有Coerce值回调以控制属性的限制。 4. 与CLR属性不同,DP具有元数据。
在实践中,我看到很多人在嵌套绑定和引发更改方面犯了许多错误,这种错误不会在DP上发生,因为它的设计和引发更改的兼容性。因此,通过一点额外的语法,您可以为应用程序提供灵活性/性能/易用性。所以无论何时都要去做。
至于ViewModel类/其他辅助类,我仍不能确定。如果将来发现有令人信服的理由,我会更新答案。 这个主题值得阅读的文章

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