2010-03-13 111 views
4

我有一些逻辑取决于两个属性被设置,因为它执行时,两个属性都有一个值。例如:如何处理MVVM ViewModel中的“SelectedItemChanged”事件?

private void DoCalc() { 
    if (string.IsNullOrEmpty(Property1) || string.IsNullOrEmpty(Property2)) 
    return; 
    Property3 = Property1 + " " + Property2; 
} 

该代码将需要每次Property1或Property2改为执行,但我无法弄清楚如何做到这一点的风格上可以接受的方式。下面是选择,因为我看到他们:

1)从视图模型

调用方法

我没有这个概念有问题,因为逻辑仍然是在视图模型 - 我不是一个“不代码隐藏“纳粹。然而,'触发'逻辑(当任何一个属性发生变化时)仍然在UI层,我不喜欢。代码隐藏应该是这样的:

void ComboBox_Property1_SelectedItemChanged(object sender, RoutedEventArgs e) { 
    viewModel.DoCalc(); 
} 

2)从属性setter

调用方法这种方法似乎是最“纯”,但它似乎也难看,仿佛逻辑是隐藏的。它应该是这样的:

public string Property1 { 
    get {return property1;} 
    set { 
    if (property1 != value) { 
     property1 = value; 
     NotifyPropertyChanged("Property1"); 
     DoCalc(); 
    } 
    } 
} 

3)挂接到PropertyChanged事件

现在,我想这可能是正确的做法,但感觉怪异挂接到在实施属性更改事件视图模型。这将是这个样子:

public ViewModel() { 
    this.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged); 
} 

void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { 
    if (e.PropertyName == "Property1" || e.PropertyName == "Property2") { 
    DoCalc(); 
    } 
} 

所以,我的问题是,如果你是通过与这一要求,你更喜欢哪一种方法,看看实施的一些源代码浏览(为什么?)。感谢您的任何意见。

回答

3

我不认为在setter中这样做很丑陋......实际上它可能是你提到的3种方法中最好的,因为当你阅读代码时,你立即看到改变Property1Property2的值将会重新计算Property3;这与其他两种方法完全不同。

但是,我不会使用这些选项。我觉得这样做的更好的办法是使Property3只读,并计算其在吸气值,根据Property1Property2

public string Property3 
{ 
    get { return Property3 = Property1 + " " + Property2; } 
} 

这样一来,在Property1Property2的制定者,你只要还需要拨打NotifyPropertyChanged以获取Property3

+1

除非第三属性是小事就像在你的榜样,二传手'Property1'和'Property2'也应该设置一些'IsProperty3Invalid'标志,这对于'Property3'吸气会检查看看是否需要再次调用“DoCalc”。 – Gabe

+0

这是一个有趣的想法(我显然没有考虑过)。我不得不考虑这个问题,因为在'真实'代码中,属性3有时由prop1和prop2设置,但如果它不是由这些条件设置的,则用户必须手动填写它。可以使用这种方法来完成......我会对其进行编码并查看它的外观。好东西。 – Travis

+0

标记为正确的,只是给你一些道具,但不知道我100%同意。需要浸泡在它:)。 – Travis

0

是@Thomas是对的。方法2是进入WPF环境的完美方式。假设您已将ListBox.SelectedValue TwoWay绑定到Property1

您的(1)无效,因为它将业务逻辑暴露给View。 (3)是一个不必要的事件处理,无论如何都是由Property1设置程序代码触发的。所以最好直接从Setter中调用它。所以MVVM的方式是(2)

1

(2)是我平常的做法。

这就是说,它让我想知道是否有可能是另一种方式使用的Rx框架做这种类型的事情:http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

原来这就是我想出了(警告 - 不要做这种方式);!)

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

有趣。我不会那样做;-) – Travis

相关问题