实现属性变化自动通知的最简单方法

28

我知道有一些解决方案可以实现INotifyPropertyChanged,但它们都不如这样简单:引用此库,创建/添加此属性,完成(我在考虑面向方面的编程)。有没有人知道一个真正简单的方法来做到这一点?如果解决方案是免费的,那就更好了。

以下是一些相关链接(其中没有提供足够简单的答案):

6个回答

31

试一下这个https://github.com/Fody/PropertyChanged

它会编织实现INotifyPropertyChanged接口的类型的所有属性,甚至处理依赖项。

你的代码

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

}

哪些内容会被编译

public class Person : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    private string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }    

    public void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));    
        }
    }
}

或者你可以使用属性来进行更精细的控制。


Fody 的功能比较有限,它只能处理类本身的依赖关系,并且无法传播那些依赖于某个嵌套视图模型属性的属性。而 PostSharp 可以提供这样一种功能。 - KolA

3

谢谢Reed。我添加了一条注释,澄清理想解决方案应该比200美元(用于PostSharp)便宜得多。我知道有一个免费的PS版本,但我无法用那个版本实现我的目标。 - Pat

3

这里是我的代码和截图供参考,Simon的回答是解决方案。我正在使用Prism(带有MEF - 忽略类上的属性),所以我从NotificationObject继承INotifyPropertyChanged。(它定义了一个RaisePropertyChanged方法,因此您需要在项目文件中告诉NotifyPropertyWeaver。)

这个类

using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.ViewModel;

[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class SignControllerViewModel : NotificationObject
{
    public string Uri { get; set; }
}

The Project File

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <!-- snipped -->
    <UsingTask TaskName="NotifyPropertyWeaverMsBuildTask.WeavingTask" AssemblyFile="$(SolutionDir)lib\NotifyPropertyWeaverMsBuildTask.dll" />
    <Target Name="AfterBuild">
        <NotifyPropertyWeaverMsBuildTask.WeavingTask
                    TargetPath="$(TargetPath)"
                    TryToWeaveAllTypes="true"
                    EventInvokerName="RaisePropertyChanged"
                    MessageImportance="High"/>
    </Target>
</Project>

反射器代码

在实现INPC后的代码。


我将很快创建一个新的维基页面,展示Prism、Caliburn、Caliburn Micro和MVVMLight的推荐设置。 - Simon
我建议尝试不要使用NotificationObject。它只提供了RaisePropertyChanged方法。如果您只在模型中实现INotifyPropertyChanged,NotifyPropertyWeaver将为您注入该方法。 - Simon

2
有一个名为Polymod的项目,它提供了您想要的功能。它具有一些很酷的功能,例如定义自更新公式。例如,如果Sum = A + B,则在更改A或B时会调用Sum的PropertyChanged方法。
它还可以与Rules Engine无缝配合使用,为您提供验证功能。 由于它是可扩展的,因此也可以使用其他验证框架。
这是最好的面向切面编程!

2

还有一个UpdateControls.NET。我没有使用过它,看起来比notifypropertyweaver更加繁琐,但可能很不错。以下是该网站的介绍:

无需INotifyPropertyChanged即可进行数据绑定

Update Controls不需要你实现INotifyPropertyChanged或声明DependencyProperty。它直接连接控件到CLR属性。通过中间代码层发现数据依赖关系。这使其非常适合模型/视图/视图模型模式;在ViewModel中不需要额外的代码,它位于Model和View之间。

包装您窗口的DataContext。这个包装器不仅为您对象的所有属性实现了INotifyPropertyChanged,而且还自动检测它们对其他属性的依赖关系。没有基类或接口需要实现。


1
感谢提及。Update Controls是一个依赖跟踪库。但它不是INotifyPropertyChanged的即插即用实现。是的,它比Notify Property Weaver更费力。所以它并不完全符合你在问题中所要求的。 - Michael L Perry

1

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