【问题标题】:Should ViewModel class implement INotifyPropertyChanged or can I use Object composition?ViewModel 类应该实现 INotifyPropertyChanged 还是可以使用对象组合?
【发布时间】:2016-06-13 20:25:20
【问题描述】:

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

我有这门课:

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 类中实现它。

要使用这个类,我使用继承:

public class Presenter : ObservableObject
{
    private string _someText;

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

但是,有没有办法通过对象组合来使用ObservableObject

我将对象组合理解为在 Presenter 类中创建 ObservableObject 的私有对象实例而不是继承。

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

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

【问题讨论】:

  • 我过去使用过ReSharper,它在对象上使用注释来提供INotifyPropertyChanged 功能。但是我想使用我自己的实现,因为 resharper 并不总是会给我使用注释的选项,它会归结为操作已编译的程序集并将适当的函数插入到正确的位置。
  • 我更新了我的问题,提供了更多细节。
  • 您的VM 需要实现INPC 的原因是因为UI 在使用Binding 时会使用该事件来刷新屏幕。如果您不使用 Binding 并且仅使用代码隐藏,那么可以,您的 VM 不需要 INPC 实现。
  • 这不是我问的关于继承和对象组合与已实现 INotifyPropertyChanged 接口和 ViewModel 类的对象的重复问题。请仔细阅读我的问题。

标签: c# wpf inheritance mvvm composition


【解决方案1】:

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

我不知道组合的方法,但这是我所知道的最好的方法。因为它有一些额外的好处(克隆很容易)

public abstract class BindingBase : INotifyPropertyChanged
{
    private IDictionary<string, object> _backingFields;
    private IDictionary<string, object> BackingFields
    {
        get { return _backingFields ?? (_backingFields = new Dictionary<string, object>(); }
    }    
protected T GetValue<T>(Expression<Func<T>gt; expr) { var name = GetName(expr); return BackingFields.Contains(name) ? (T)BackingFields[name].Value : default(T); }
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
BackingFields[name] = value; RaisePropertyChanged(name); }
private void RaisePropertyChanged(string name) { // you know this part
}
private string GetName (Expression<Func<T> expr) { // implementation can be found via google } }
使用非常简单。
public class BindingChild : BindingBase
{
    public string SampleProperty
    {
        get { return GetValue(() => SampleProperty); }
        set { SetValue(() => SampleProperty, value); }
    }
}

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-03-09
      • 2010-10-20
      • 2019-09-25
      • 1970-01-01
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      • 2020-07-12
      • 1970-01-01
      相关资源
      最近更新 更多