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>
我正在使用 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>