我有一些逻辑依赖于设置的两个属性,因为它在两个属性都有值时执行。例如:
private void DoCalc() {
if (string.IsNullOrEmpty(Property1) || string.IsNullOrEmpty(Property2))
return;
Property3 = Property1 + " " + Property2;
}
每次Property1或Property2发生变化时都需要执行该代码,但我无法以风格上可接受的方式确定如何执行此操作。以下是我看到的选择:
1)来自ViewModel的调用方法
我在概念上没有问题,因为逻辑仍然在ViewModel中 - 我不是'没有代码隐藏'的纳粹。但是,'触发'逻辑(当属性发生变化时)仍在UI层中,我不喜欢。代码隐藏看起来像这样:
void ComboBox_Property1_SelectedItemChanged(object sender, RoutedEventArgs e) {
viewModel.DoCalc();
}
2)来自Property Setter的调用方法
这种方法似乎是最“纯粹”的,但它看起来也很难看,好像逻辑是隐藏的。它看起来像这样:
public string Property1 {
get {return property1;}
set {
if (property1 != value) {
property1 = value;
NotifyPropertyChanged("Property1");
DoCalc();
}
}
}
3)进入PropertyChanged事件
我现在认为这可能是正确的方法,但在实现viewmodel中挂钩属性更改事件感觉很奇怪。它看起来像这样:
public ViewModel() {
this.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
}
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "Property1" || e.PropertyName == "Property2") {
DoCalc();
}
}
所以,我的问题是,如果您正在浏览一些具有该要求的源代码,您希望看哪种方法实现(以及为什么?)。感谢您的任何意见。
答案 0 :(得分:3)
我不认为在setter中这样做是丑陋的......实际上它可能是你提到的3种方法中最好的,因为当你阅读代码时,你会立即看到更改Property1
的值或Property2
将重新计算Property3
;对于其他两种方法,这一点并不明显。
但是,我不会使用这些选项。根据{{1}}和Property3
,我认为更好的方法是将Property1
只读,并在getter中计算其值:
Property2
这样,在public string Property3
{
get { return Property3 = Property1 + " " + Property2; }
}
和Property1
的制定者中,您只需要为Property2
拨打NotifyPropertyChanged
。
答案 1 :(得分:1)
(2)是我通常这样做的方式。
那就是说,让我想知道是否有其他方法可以使用Rx框架来完成这类事情:http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx
所以这就是我想出来的(CAVEAT - 不要这样做!);)
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
var o1 =
Observable.FromEvent<PropertyChangedEventArgs>(this, "PropertyChanged");
o1.Subscribe(e => Debug.WriteLine(e.EventArgs.PropertyName));
var o2 = o1.SkipWhile(e => e.EventArgs.PropertyName != "Property1");
var o3 = o1.SkipWhile(e => e.EventArgs.PropertyName != "Property2");
var o4 = o1.SkipWhile(e => e.EventArgs.PropertyName != "Result");
var o5 = Observable.CombineLatest(o2, o3, (e1, e2) => DoStuff()).TakeUntil(o4);
o5.Subscribe(o => Debug.WriteLine("Got Prop1 and Prop2"));
}
public string DoStuff()
{
return Result = string.Concat(Property1, Property2);
}
private string _property1;
public string Property1
{
get { return _property1; }
set
{
_property1 = value;
OnNotifyPropertyChanged("Property1");
}
}
private string _property2;
public string Property2
{
get { return _property2; }
set
{
_property2 = value;
OnNotifyPropertyChanged("Property2");
}
}
private string _result;
public string Result
{
get { return _result; }
set
{
_result = value;
OnNotifyPropertyChanged("Result");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string name)
{
var handler = PropertyChanged;
if(handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
答案 2 :(得分:0)
是的@Thomas是对的。方法2是进入WPF环境的最佳方式。如果已将ListBox.SelectedValue两个绑定添加到Property1
您的(1)无效,因为这会将业务逻辑暴露给View。 (3)是一个不必要的事件处理,无论如何由Property1 setter代码触发。所以最好直接从Setter调用它。所以MVVM方式是(2)