简体   繁体   English

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

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

I'm developing a MVVM WPF application with C# and .NET Framework 4.6. 我正在使用C#和.NET Framework 4.6开发MVVM WPF应用程序。

I have this 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));
    }
}

I have implemented here INotifyPropertyChanged because I don't want to implement it in all of my ViewModel classes. 我在这里实现了INotifyPropertyChanged因为我不想在所有ViewModel类中都实现它。

To use this class, I use inherit: 要使用此类,我使用继承:

public class Presenter : ObservableObject
{
    private string _someText;

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

But, is there a way to use ObservableObject using object composition? 但是,有没有一种方法可以通过对象组合使用ObservableObject

I understand object composition as instead of inherit, create a private object instance of ObservableObject in class Presenter . 我了解对象组成是继承类,而不是在Presenter类中创建ObservableObject的私有对象实例。

I'm not sure if any ViewModel class should implement INotifyPropertyChanged . 我不确定是否有任何ViewModel类应实现INotifyPropertyChanged

UPDATE: 更新:
This is not a duplicate question . 这不是一个重复的问题 I'm asking if a ViewModel has always to implement INotifyPropertyChanged interface or instead, I can use Object composition. 我问一个ViewModel是否必须始终实现INotifyPropertyChanged接口,或者可以使用对象组合。 I have explained before. 我已经解释过了。 Please, read carefully my question. 请仔细阅读我的问题。

Well, ... ViewModels are best to be viewed as Composition, but the notification part should be an implementation of the Interface (or in your case inheritance). 好吧,... ViewModels最好被看作是Composition,但是通知部分应该是Interface的实现(或者在您的情况下是继承)。 You have your DTOs and your ViewModels would be a composition of the DTOs, depending on the scenario. 您拥有DTO,根据情况,您的ViewModels将是DTO的组成。

This implementation of the same stuff can be tedious, but for WPF is still necessary. 相同内容的实现可能很乏味,但是对于WPF仍然是必需的。 What you can do to simplify the process is to use Veawrs like Fody . 你能做些什么来简化这个过程是使用Veawrs像Fody It changes your observation of the ViewModel. 它改变了您对ViewModel的观察。 All of the properties of the VM are by default observable properties, but you exclude the ones you do not want to, or you can define for one property to let the UI know that it should also update others. 默认情况下,VM的所有属性都是可观察的属性,但是您可以将不需要的属性排除在外,或者可以为一个属性定义以让UI知道它也应该更新其他属性。

It keeps the code very clean and simple. 它使代码非常干净和简单。 You will not need to implement the Interface, but it will be inherited in build time if you give the class the needed attribute. 您无需实现接口,但是如果您为类提供所需的属性,它将在构建时继承。

If you want to improve the robustness by avoiding code duplication and using strings in code. 如果要通过避免代码重复并在代码中使用字符串来提高鲁棒性。 Then you could use the following base class. 然后,您可以使用以下基类。

I don't know an approach with composition, but this one is the best I know. 我不知道采用合成的方法,但这是我所知道的最好的方法。 Since it has some additional benefits (Cloning made easy aso) 由于它还有一些其他好处(将aso复制变得容易)


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 } }
Usage is quite easy. 使用非常简单。
 public class BindingChild : BindingBase { public string SampleProperty { get { return GetValue(() => SampleProperty); } set { SetValue(() => SampleProperty, value); } } } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM