微软应该为INotifyPropertyChanged实现一些时髦的东西,就像在自动属性中,只需要指定{get;设置;通知;} 我认为这样做很有意义。或者做这个手术有什么并发症吗?

我们能在属性中实现类似notify的东西吗。在你的类中实现INotifyPropertyChanged是否有一个优雅的解决方案,或者唯一的方法是在每个属性中引发PropertyChanged事件。

如果不是,我们可以写一些东西来自动生成一段代码来引发PropertyChanged事件?


当前回答

它是2022。现在有了官方的解决方案。

使用Microsoft MVVM工具包中的MVVM源生成器。

This

[ObservableProperty]
private string? name;

将生成:

private string? name;

public string? Name
{
    get => name;
    set
    {
        if (!EqualityComparer<string?>.Default.Equals(name, value))
        {
            OnNameChanging(value);
            OnPropertyChanging();
            name = value;
            OnNameChanged(value);
            OnPropertyChanged();
        }
    }
}

// Property changing / changed listener
partial void OnNameChanging(string? value);
partial void OnNameChanged(string? value);

protected void OnPropertyChanging([CallerMemberName] string? propertyName = null)
{
    PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
}

protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

它支持。net标准2.0和。net >= 5.0。

其他回答

看这里:http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx

它是用德语写的,但你可以下载ViewModelBase.cs。cs-File中的所有注释都是用英语写的。

使用这个ViewModelBase-Class,可以实现类似于众所周知的依赖属性的可绑定属性:

public string SomeProperty
{
    get { return GetValue( () => SomeProperty ); }
    set { SetValue( () => SomeProperty, value ); }
}

我建议使用ReactiveProperty。 这是除了Fody之外最短的方法。

public class Data : INotifyPropertyChanged
{
    // boiler-plate
    ...
    // props
    private string name;
    public string Name
    {
        get { return name; }
        set { SetField(ref name, value, "Name"); }
    }
}

而不是

public class Data
{
    // Don't need boiler-plate and INotifyPropertyChanged

    // props
    public ReactiveProperty<string> Name { get; } = new ReactiveProperty<string>();
}

(文档)

我在我的基本库中创建了一个扩展方法用于重用:

public static class INotifyPropertyChangedExtensions
{
    public static bool SetPropertyAndNotify<T>(this INotifyPropertyChanged sender,
               PropertyChangedEventHandler handler, ref T field, T value, 
               [CallerMemberName] string propertyName = "",
               EqualityComparer<T> equalityComparer = null)
    {
        bool rtn = false;
        var eqComp = equalityComparer ?? EqualityComparer<T>.Default;
        if (!eqComp.Equals(field,value))
        {
            field = value;
            rtn = true;
            if (handler != null)
            {
                var args = new PropertyChangedEventArgs(propertyName);
                handler(sender, args);
            }
        }
        return rtn;
    }
}

这适用于. net 4.5,因为有CallerMemberNameAttribute。 如果你想在一个早期的。net版本中使用它,你必须改变方法声明:…,[CallerMemberName] string propertyName = "",………,字符串propertyName…

用法:

public class Dog : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            this.SetPropertyAndNotify(PropertyChanged, ref _name, value);
        }
    }
}

我正在编写一个处理INotifyPropertyChanged的库,主要思想是使用动态代理来通知更改。

回购在这里:CaulyKan/NoMorePropertyChanged

使用这个库,你可以写:

    public dynamic Test1Binding { get; set; }
    public TestDTO Test1
    {
        get { return (TestDTO)Test1Binding; }
        set { SetBinding(nameof(Test1Binding), value); }
    }

然后将所有绑定和修改转到Test1Binding,无论TestDTO有多复杂,它都会自动通知PropertyChange和CollectionChanged。

它还可以处理依赖关系。

    [DependsOn("Test1Binding.TestString")]
    public string Test2
    {
        get { return Test1Binding.TestString; }
    }

请给我一些建议。

我实际上还没有机会尝试这个自己,但下次我设置一个大需求的INotifyPropertyChanged项目,我打算写一个Postsharp属性,将在编译时注入代码。喜欢的东西:

[NotifiesChange]
public string FirstName { get; set; }

将成为:

private string _firstName;

public string FirstName
{
   get { return _firstname; }
   set
   {
      if (_firstname != value)
      {
          _firstname = value;
          OnPropertyChanged("FirstName")
      }
   }
}

我不确定这在实践中是否有效,我需要坐下来尝试一下,但我不明白为什么不。我可能需要让它接受一些参数的情况下,超过一个OnPropertyChanged需要被触发(如果,例如,我有一个FullName属性在上面的类)

目前我在Resharper使用一个自定义模板,但即使这样,我也厌倦了我所有的属性太长。


啊,一个快速的谷歌搜索(我应该在写这篇文章之前做的)显示至少有一个人在这里之前做过类似的事情。跟我想的不完全一样,但也足以证明这个理论是正确的。