代码之家  ›  专栏  ›  技术社区  ›  tsimon

如何处理MVVM ViewModel中的“SelectedItemChanged”事件?

  •  4
  • tsimon  · 技术社区  · 16 年前

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

    每次Property1或Property2发生更改时,都需要执行该代码,但我很难弄清楚如何以一种风格上可以接受的方式执行它。以下是我看到的选择:

    1) 从ViewModel调用方法

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

    2) 从属性设置器调用方法

    这种做法看似最“纯粹”,但也显得丑陋,似乎逻辑是隐藏的。它看起来是这样的:

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

    3) 钩住PropertyChanged事件

    我现在认为这可能是正确的方法,但是在实现viewmodel中连接到property changed事件感觉很奇怪。它看起来像这样:

    public ViewModel() {
      this.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
    }
    
    void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) {
      if (e.PropertyName == "Property1" || e.PropertyName == "Property2") {
        DoCalc();
      }
    }
    

    3 回复  |  直到 16 年前
        1
  •  3
  •   Thomas Levesque    16 年前

    我不认为在二传中做是丑陋的。。。实际上,这可能是您提到的3种方法中最好的一种,因为当您阅读代码时,您会立即看到更改 Property1 或 Property2 Property3 ; 这在其他两种方法中一点也不明显。

    物业3 物业1 和 :

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

    物业1 和 物业2 NotifyPropertyChanged 对于 物业3 也

        2
  •  1
  •   JerKimball    16 年前

    (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));
            }
        }
    }
    
        3
  •  0
  •   Jobi Joy    16 年前

    是的,托马斯是对的。在WPF环境中,方法2是最理想的方法。前提是已将ListBox.SelectedValue双向绑定添加到属性1

    您的(1)无效,因为它将业务逻辑公开给视图(3) 是一个不必要的事件处理,它无论如何都是由Property1 setter代码触发的。所以最好直接从塞特那叫出来。所以MVVM的方法是(2)