INotifyPropertyChanged 订阅自我

Posted

技术标签:

【中文标题】INotifyPropertyChanged 订阅自我【英文标题】:INotifyPropertyChanged subscribing to self 【发布时间】:2011-08-04 08:40:42 【问题描述】:

我有一个实现 INotifyPropertyChanged 的​​类。我正在使用 Simon Cropp 的出色 NotifyPropertyWeaver 将 INotifyPropertyChanged 代码注入到属性中。但是,我现在需要修改一组属性的设置器,以便在设置完成后都执行相同的操作。修改 setter 需要创建支持字段、实现 get、实现 set 等,所有这些都具有相同的实现,除了支持字段的名称。我只是通过使用NotifyPropertyWeaver 避免了所有这些。

相反,我可以让我的班级订阅它自己的 PropertyChanged 事件并在事件处理程序中处理更改后操作。这是安全的事情吗?我意识到如果我的操作修改了我正在观察的属性之一,我将不得不注意导致堆栈溢出的无限递归。还有其他需要注意的问题吗?

这是一个例子

public class Foo : INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    public Prop1  get; set; 
    public Prop2  get; set; 
    public Prop3  get; set; 
    public Prop4  get; set; 

    public Foo()
        this.PropertyChanged +=
            new PropertyChangedEventHandler(Foo_PropertyChanged);
    

    private void Foo_PropertyChanged(object sender, PropertyChangedEventArgs e)
    
        switch (e.PropertyName)
        
            case "Prop1":
            case "Prop2":
            case "Prop3":
                DoSomething();
                break;
            case "Prop4":
                DoSomethingElse();
                break;
        
    

    private void DoSomething()
    
        ....
    

    private void DoSomethingElse()
    
        ....
    

编辑

Joel Lucsy 好心指出我不需要订阅该活动。我一直允许 NotifyPropertyWeaver 注入 OnPropertyChanged。相反,我可以自己实现 OnPropertyChanged 来完成同样的事情。

更新代码:

public class Foo : INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    public Prop1  get; set; 
    public Prop2  get; set; 
    public Prop3  get; set; 
    public Prop4  get; set; 

    private void OnPropertyChanged(string propertyName)
    
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
        switch (propertyName)
        
            case "Prop1":
            case "Prop2":
            case "Prop3":
                DoSomething();
                break;
            case "Prop4":
                DoSomethingElse();
                break;
        
    

    private void DoSomething()
    
        ....
    

    private void DoSomethingElse()
    
        ....
    

【问题讨论】:

您能否提供一个更真实的代码示例,以便我更好地了解您想要实现的目标? 【参考方案1】:

一方面,您只需实现 OnPropertyChanged 而不必使用该事件。

第二,这被认为是不好的形式。 NotifyPropertyWeaver 会检查代码并检测属性之间的依赖关系。例如,如果您在属性 B 的代码中使用属性 A,NotifyPropertyWeaver 将在 A 的代码中为 B 添加第二个 OnPropertyChanged,以确保所有内容都已更新。

简而言之,不要那样做,输入所有内容。

【讨论】:

好点,如果我显式实现 OnPropertyChanged 而不是期望 NotifyPropertyWeaver 为我完成,则无需订阅该事件。 我同意 NotifyPropertyWeaver 将处理属性之间的依赖关系。然而,这不是我想要完成的。拥有 10 个类,每个类包含 5 个属性,除了支持字段名称外,它们都具有完全相同的 12 行实现,不仅乏味,而且容易出错。我希望让事情更易于阅读和维护,这就是我使用 NotifyPropertyWeaver 的原因。 您可以尝试几件事。 PostSharp 将允许您比 NotifyPropertyWeaver 更灵活。或者您可以尝试我认为称为 T4 的内置模板。或者使用sn-ps生成代码。 @Joel 您能否详细说明 PostSharp 在这种情况下如何比 NPW 更灵活?我很想知道我可能缺少哪些功能 @Simon PostSharp 可以做的很多不仅仅是INotifyPropertyChanged。一些具体场景可以在here找到。【参考方案2】:

我已经完成了这个/使用了以前做过的代码,并且没有注意到代码方面有很大的副作用。根据属性的数量,您可能会看到性能下降,但它可能会很小。我注意到的是,在查看代码时,在使用此模式时为什么会发生效果并不总是很清楚。你必须注意的是你是如何设计你的课程的。当您快速组合类时,自动属性很好,但它们可能会成为您整体设计的障碍。我通常不使用它们,除非它是一个对象的快速模型,或者它是我用来传输数据的一个非常简单的对象。您必须问自己的问题是,您是否以这种方式设计对象,是因为它最适合您的代码、程序、样式,还是因为您正在尝试使用特定功能,即自动属性。

要考虑的一件事是,您是要对每个字段执行相同的操作,还是要执行不同的操作?如果你有不同的动作,你很快就会得到一个大而笨重的方法。如果它们是相同的操作,则可能更易于管理。

我实现INotifyProperty接口的正常方式是创建一个更改字段的方法,执行通知,也可以在更改完成后带一个Action执行。这避免了拥有所有大的条件语句并提供对动作的细粒度控制,但具有足够的细粒度控制以完全灵活。如果我要创建很多相关的对象,我通常也只是创建一个基类来继承所有这些对象,并将此更改方法作为受保护的方法,因此我不必每次重新实现一次模式类。

【讨论】:

自动属性如何成为设计的障碍?如果您需要向 getter 或 setter 添加逻辑/检查,您不会简单地创建一个支持字段并将属性扩展为显式实现吗? @Aydsman 我想说的是,如果您围绕它们进行设计以保留它们,而不是用支持字段替换它们,它们可能会成为障碍。当您不需要支持字段时,它们很棒(喜欢它们),但您不应该仅仅因为想要使用它们而避免制作支持字段。 你能告诉我关于你上面提到的行动方法的任何信息吗? @DarthChucks 该模式并非来自任何地方,而是从经验和需求中有机地发展而来。我相信有人也在某处写过它,我只是没有想到它的参考资料。如果您想要一个如何实现它的示例,我可以提供它。 我明白了。抱歉,我没有从你的帖子中明白这一点。我绝对同意;为了保留汽车属性而进行的黑客攻击是愚蠢和危险的。自动属性的美妙之处在于您可以在不破坏 API 兼容性的情况下扩展它们。【参考方案3】:

我已向 NotifyPropertyWeaver 添加了 On_PropertyName_Changed 功能 http://code.google.com/p/notifypropertyweaver/wiki/On_PropertyName_Changed

所以如果你写这个

public class Foo : INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    public string Prop1  get; set; 
    public string Prop2  get; set; 
    public string Prop3  get; set; 
    public string Prop4  get; set; 

    void OnProp3Changed()
    
    

    void OnProp4Changed()
    
    

对 OnProp3Changed 和 OnProp4Changed 的​​调用将分别注入到 Prop3 和 Prop4 的集合中。

【讨论】:

以上是关于INotifyPropertyChanged 订阅自我的主要内容,如果未能解决你的问题,请参考以下文章

使用属性... INotifyPropertyChanged

INotifyPropertyChanged WPF

INotifyPropertyChanged的作用

INotifyPropertyChanged WPF

INotifyPropertyChanged 和 DependencyProperty 有啥关系?

为啥 ViewModel 应该实现 INotifyPropertyChanged?