2

我对 MVVM 设计有一个大问题。我试图在我的 ViewModel 中捕获我的内部嵌套对象的每个 PropertyChanged,包括它们嵌套对象的进一步属性更改,但我不知道该怎么做。

这是我的结构:

class MyVM
{

  public MyVM()
  {
    this.SomeData = new SomeData();
    this.SomeData.NestedObj = new MyNestedDat();
    this.SomeData.Str = "This tiggers propertychanged inside MyDat class";
    // this triggers propertychanged event inside MyNestedDat class
    this.SomeData.NestedObj.Num = 123;
  }

  // and here should be a method where i catch all possibe propertychanges from my nested objets and their nested objets, how do i do that?

  public MyDat SomeData
  {
    get;
    set;
  }

}

class MyDat : INotifyPropertyChanged
{
  private string str;
  public string Str;
  {
    get { return this.str;}
    set
    {
      this.str = value;
      this.PropertyChanged(this, "Str");
    }
  }


  publicMyNestedDat NestedObj
  {
   get;
   set;
  }
}

class MyNestedDat : INotifyPropertyChanged
{
  private int num;
  public int Num
  {
    get{ return this.num;}
    set
    {
      this.num = value;
      this.PropertyChanged(this, "Num");
    }
  }
}

我怎样才能让它工作?我真的不知道从哪里开始。

MyNestedDat 类抛出 PropertyChanged,MyDat 类抛出 propertychanged,我想在我的视图模型中捕获它们。我怎样才能做到这一点?

4

3 回答 3

1

关于PropertyChangedEventArgsPropertyName中应该包含的内容没有明确的限制。

请参阅为嵌套(子)对象订阅 INotifyPropertyChanged

这是一个例子:

class A : BaseObjectImplementingINotifyPropertyChanged {

  private string m_name;
  public string Name {
    get { return m_name; }
    set {
      if(m_name != value) {
        m_name = value;
        RaisePropertyChanged("Name");
      }
    }
  }
}

class B : BaseObjectImplementingINotifyPropertyChanged {

  private A m_a;
  public A A {
    get { return m_a; }
    set {
      if(m_a != value) {
        if(m_a != null) m_a.PropertyChanged -= OnAPropertyChanged;
        m_a = value;
        if(m_a != null) m_a.PropertyChanged += OnAPropertyChanged;
        RaisePropertyChanged("A");
      }
    }
  }

  private void OnAPropertyChanged(object sender, PropertyChangedEventArgs e) {
    RaisePropertyChanged("A." + e.PropertyName);
  }

}


B b = new B();
b.PropertyChanged += (s, e) => { Console.WriteLine(e.PropertyName); };
b.A.Name = "Blah"; // Will print "A.Name"
于 2013-04-09T14:47:47.630 回答
1

这里最好的做法是将ModelViewModel的概念分开。

通过拥有一个ViewModel比您更平坦的对象,Model您可以避免这种情况。使用像Automapper这样的自动映射工具可以让您映射ModelViewModel,反之亦然。

https://github.com/AutoMapper/AutoMapper/wiki/Flattening

class MyDatViewModel : INotifyPropertyChanged
{
    public string Str
    {
        // ... Get Set
    }

    public int NestedObjNum
    {
        // ... Get set
    }
}

// Configure AutoMapper

Mapper.CreateMap<MyDat, MyDatViewModel>();

// Perform mapping

MyDatViewModel viewModel = Mapper.Map<MyDat, MyDatViewModel>(someData);
于 2013-04-09T15:40:33.377 回答
1

在我看来,您所问的问题存在一些概念性问题。想象一下,您得到了一个适用于您的场景(您对此感到满意)的解决方案,并考虑以下几点:

  • 如果添加另一层会发生什么?你还期望它同样工作吗?
  • 是否应该传播属性更改(viewModel1.propA通知viewModel2.PropA)?
  • 是否应该转换属性更改(viewModel1.SomeProp通知ViewModel2.AnotherProp)?
  • 性能是一个问题吗?如果您需要通过多个级别传播属性更改事件,这将如何执行?

这应该敲响警钟,即当前的方法不是正确的道路。

您需要的是一种以松散耦合的方式在您的视图模型之间提供通信的方法,以便您的视图模型甚至不需要知道彼此的存在。这样做的美妙之处在于,这也适用于其他情况,而不仅仅是属性更改。

对于您的属性更改事件,一个 viewModel 想知道什么时候发生(它可能不是属性更改事件,请记住)。这意味着另一个 viewModel 需要某种方式说“嘿,属性已更改”(或“我的状态已更改”、“该数据库调用已完成”等)。

现在在 C# 中,您可以提供提供此功能的事件....除了,现在您的对象相互了解,这给您留下了与以前相同的问题。

为了克服这个问题,你需要另一个对象,一个中介者(在这个例子中我们称之为Messenger),它的唯一目的是处理对象之间的消息传递,这样它们就可以在彼此不知道的情况下生活。

总体思路是这样的。在提供通知的 viewModel 中,您可能会执行以下操作:

public string MyProp
{
    get { return _myProp; }
    set
    {
        _mProp = value;
        OnPropertyChanged("MyProp");
        Messenger.PostMessage(new VMChangedMessage { ViewModel = this, PropertyName = "MyProp" });
    }
}

在对事件感兴趣的 viewModel 中,您可能会执行以下操作:

public class ViewModel2
{
    public ViewModel2()
    {
        Messenger.Subscribe<VMChangedMessage>(handleMessage);
    }

    private void handleMessage(VMChangedMessage msg)
    {
        // Do something with the information here...
    }
}

请注意,两个视图模型从不相互引用。它们现在是松耦合的。

已经有许多预先存在的实现可用,创建自己的实现并不困难(信使基本上保留对某个消息感兴趣的对象列表,并在需要通知相关方时迭代该列表) . 有一些事情可以不同地实现(有些实现只是传递字符串消息而不是将信息封装在对象中,有些实现自动处理观察者的清理)。

我会推荐使用 Josh Smiths (excellent) MVVM Foundation,它包括一个信使类。它也是开源的,所以你可以看到它是如何工作的。

于 2013-04-09T16:51:16.497 回答