ViewModel class 应该实现 INotifyPropertyChanged 还是我可以使用对象组合?

Should ViewModel class implement INotifyPropertyChanged or can I use Object composition?

我正在使用 C# 和 .NET Framework 4.6 开发 MVVM WPF 应用程序。

我有这个 class:

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

我在这里 INotifyPropertyChanged 实现了,因为我不想在我的所有 ViewModel classes 中实现它。

要使用此 class,我使用继承:

public class Presenter : ObservableObject
{
    private string _someText;

    public string SomeText
    {
        get { return _someText; }
        set
        {
            _someText = value;
            RaisePropertyChangedEvent("SomeText");
        }
    }
}

但是,有没有办法使用 ObservableObject 使用对象组合?

我将对象组合理解为在 class Presenter.

中创建 ObservableObject 的私有对象实例而不是继承

我不确定是否有任何 ViewModel class 应该实现 INotifyPropertyChanged

更新:
这不是重复问题。我在问 ViewModel 是否必须始终实现 INotifyPropertyChanged 接口,或者我可以使用对象组合。我之前已经解释过了。请仔细阅读我的问题。

嗯,...ViewModels 最好被视为组合,但通知部分应该是接口的实现(或者在您的情况下是继承)。你有你的 DTO,你的 ViewModel 将是 DTO 的组合,具体取决于场景。

同样的东西的这种实现可能很乏味,但对于 WPF 来说仍然是必要的。你可以做些什么来简化这个过程是使用像 Fody 这样的 Veawrs。它改变了您对 ViewModel 的观察。默认情况下,VM 的所有属性都是可观察的属性,但您可以排除不需要的属性,或者您可以定义一个 属性 让 UI 知道它也应该更新其他属性.

它使代码非常干净和简单。您不需要实现该接口,但如果您为 class 提供所需的属性,它将在构建时被继承。

如果您想通过避免代码重复和在代码中使用字符串来提高健壮性。然后你可以使用下面的基础 class.

我不知道组合的方法,但这是我所知道的最好的方法。因为它有一些额外的好处(克隆变得容易 a.s.o。) <pre> public abstract class BindingBase : INotifyPropertyChanged { private IDictionary<string, object> _backingFields; private IDictionary<string, object> BackingFields { get { return _backingFields ?? (_backingFields = new Dictionary<string, object>(); } } <br> protected T GetValue<T>(Expression<Func<T>gt; expr) { var name = GetName(expr); return BackingFields.Contains(name) ? (T)BackingFields[name].Value : default(T); } <br> protected void SetValue<T>(Expression<Func<T>gt; expr, T value) { var name = GetName(expr); if (BackingFields.Contains(name) && BackingFields[name].Value.Equals(value)) return; // return without doing anything, since the value is not changing <br> BackingFields[name] = value; RaisePropertyChanged(name); }<br> private void RaisePropertyChanged(string name) { // you know this part<br> }<br> private string GetName (Expression<Func<T> expr) { // implementation can be found via google } } </pre> 使用非常简单。 <pre> public class BindingChild : BindingBase { public string SampleProperty { get { return GetValue(() => SampleProperty); } set { SetValue(() => SampleProperty, value); } } } </pre>