2016-03-01 58 views
2

我正在用C#和.NET Framework 4.6開發MVVM WPF應用程序。應該ViewModel類實現INotifyPropertyChanged還是可以使用Object組合?

我有這個類:

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

UPDATE:
這不是一個重複的問題。我問,如果一個ViewModel總是實現INotifyPropertyChanged接口,或者,我可以使用Object組合。我已經解釋過。請仔細閱讀我的問題。

+0

我在過去曾使用ReSharper來對對象使用註釋來提供INotifyPropertyChanged功能。但是我想使用自己的實現,因爲resharper並不總是會給我使用註釋的選項,並且它會涉及到編譯程序集的操作並在適當的位置插入適當的函數。 – XAMlMAX

+0

我已更新我的問題,並提供更多詳細信息。 – VansFannel

+2

您的'VM'需要實現'INPC'的原因是,當使用'Binding'時,UI將使用該事件來刷新屏幕。如果你不使用綁定,只有代碼隱藏,那麼你的'VM'不需要'INPC'實現。 – XAMlMAX

回答

0

嗯,... ViewModels最好被視爲組合,但通知部分應該是接口的實現(或在你的情況下繼承)。你有你的DTOs,你的ViewModels將會是DTOs的組合,這取決於場景。

同樣的東西的這種實現可能是乏味的,但對於WPF仍然是必要的。你可以做什麼來簡化這個過程是使用像Fody Veawrs。它改變了你對ViewModel的觀察。虛擬機的所有屬性默認都是可觀察的屬性,但是你排除了你不想要的屬性,或者你可以定義一個屬性讓UI知道它也應該更新其他屬性。

它使代碼非常乾淨和簡單。您不需要實現接口,但是如果您爲該類提供所需的屬性,它將在構建時被繼承。

0

如果您想通過避免代碼重複並在代碼中使用字符串來提高健壯性。然後你可以使用下面的基類。

我不知道有構圖的方法,但是這個是我所知道的最好的。由於它有一些額外的好處(克隆使輕鬆a.s.o.)

 
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); } 
    } 
} 

相關問題