何时使用 WPF 依赖属性与 INotifyPropertyChanged

Posted

技术标签:

【中文标题】何时使用 WPF 依赖属性与 INotifyPropertyChanged【英文标题】:When to use a WPF Dependency Property versus INotifyPropertyChanged 【发布时间】:2011-04-02 20:19:08 【问题描述】:

对于在视图模型中触发INotifyPropertyChanged.PropertyChanged 的简单.NET 属性何时足够,人们是否有任何指导?那么你什么时候想升级到一个完整的依赖属性呢?还是 DP 主要用于查看?

【问题讨论】:

【参考方案1】:

据我所知,DependencyProperty只有在你需要的时候才需要

    PropertyValue 继承 您需要允许在样式设置器中设置属性 为属性使用动画

等等。

这些功能不适用于普通属性。

【讨论】:

【参考方案2】:

有几种方法:

1.依赖属性

当您使用依赖属性时,它在具有视觉外观的元素类中最有意义 (UIElements)。

优点:

WPF 为你做逻辑工作 像动画这样的一些机制只使用依赖属性 “适合”视图模型样式

缺点:

你需要派生出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.PropertyName已更改

为具有指定名称的每个属性(例如 NameChanged)触发一个事件。事件必须具有此名称,由您来处理/提升它们。方法与 2 类似。

4.获取绑定

使用FrameworkElement.GetBindingExpression() 可以获得BindingExpression 对象 并调用BindingExpression.UpdateTarget()刷新。

第一和第二最有可能取决于您的目标。

总而言之,就是视觉 vs 数据。

【讨论】:

这是一个很好的答案,值得更多的支持!如果可以的话,我会投票两次。 :-)【参考方案3】:

DependencyProperty 如果要允许在属性上设置绑定,则需要。通常这是针对您创建的自定义UIElements。您希望人们能够将数据绑定到您的UIElements。

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

要做到这一点,需要 MyProperty 是一个依赖属性

【讨论】:

这其实是正确的答案。如果您希望属性成为绑定的目标,则只需要 DependencyProperty。除此之外,如果需要,您可以使用标准属性加上 INotifyPropertyChanged。 我很确定我用INotifyPropertyChanged 做了很多次,您的回答中是否有任何“隐藏方面”不清楚?【参考方案4】:

我看到INotifyPropertyChanged 的主要问题是,如果您的视图模型很复杂,包含许多嵌套类型,您似乎必须将PropertyChanged 事件通过层次结构向上冒泡。

【讨论】:

【参考方案5】:

正如其他答案已经充分说明了何时创建依赖属性。即

    PropertyValue 继承 您需要对属性使用绑定 为属性使用动画

对此的另一个观点/问题是“在 WPF 应用程序中,在控件中创建依赖属性是有意义的,因为它们可能会在用户交互过程中发生变化,例如高度、宽度、文本、内容、背景等 但是像 Behaviors Classes(非 UI 类)这样的其他类呢。这些类中的属性是否需要是依赖属性?”

我不会在这里说非常绝对或强调某些规则,但您应该将属性创建为 DP。从设计的角度来看,如果一个属性是 DP,它总是以 WPF 的默认形式使用/bind.i.e.

    与普通 CLR 属性相比,DP 在反映变化方面更快/更自然。 DP 具有验证机制来验证分配的值和恢复值的默认结构。 DP 具有强制值回调来控制属性的限制。 与 CLR 属性不同,DP 具有与其关联的元数据。

在实践方面,我看到人们在嵌套绑定中犯了很多错误,然后引发更改,这些错误不会发生在 DP 中,因为它的设计和引发更改本身的兼容性。因此,通过一些额外的语法,您可以为您的应用程序带来灵活性/性能/易用性。所以去任何负担得起的地方。

仍然不能确定 ViewModel 类/其他辅助类。如果将来找到令人信服的理由,将更新答案。

Just a post worth reading on this topic

【讨论】:

以上是关于何时使用 WPF 依赖属性与 INotifyPropertyChanged的主要内容,如果未能解决你的问题,请参考以下文章

WPF: 只读依赖属性的介绍与实践

什么时候应该在 WPF 中使用依赖属性?

什么时候应该在 WPF 中使用依赖属性?

WPF的依赖项属性

WPF: 只读依赖属性的介绍与实践

WPF--依赖属性