MVVM和INotifyPropertyChanged的问题(MVVM and INotifyPro

2019-08-20 23:22发布

我有一个MVVM设计的一个大问题。 我试图抓住每一个我的PropertyChanged内部嵌套的对象,包括futhermore propertchanged其嵌套对象的,我的视图模型里面,但我不知道该怎么做。

这里是我的结构:

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,我想赶上他们我的视图模型内。 我怎样才能做到这一点?

Answer 1:

在我看来,有一些概念性的东西错了,你是问。 试想一下,你会得到您的方案作品(你是满意)的解决方案,并考虑以下因素:

  • 如果添加了另一个层会发生什么? 你还期望它的工作一样吗?
  • 如果属性更改传播( viewModel1.propA通知viewModel2.PropA )?
  • 如果属性更改转化( viewModel1.SomeProp通知ViewModel2.AnotherProp )?
  • 是性能的关注? 这将如何执行,如果你需要通过多层次传播的属性更改事件?

这应该是提高了警钟,目前的做法是不是踩着正确的道路。

你需要的是一种提供松散耦合的方式您的ViewModels之间的沟通,使你的ViewModels甚至不需要知道彼此的存在。 这样做的好处是,这也将在其他情况下的工作不只是属性更改。

为了您的财产的情况下改变的事件,一个视图模型想知道有事时 (这可能是比属性更改事件以外的东西,记住)。 这意味着其他视图模型需要说:“嘿,属性已经改变”的一些方法(或“我的状态已经改变”,“那数据库调用已完成”等)。

现在,在C#中,你可以提供提供该功能....只是,现在你的对象知道对方这让你与你之前有同样的问题的事件。

为了克服这个问题,你需要另一个对象,调解员(可以称之为Messenger在这个例子中),其唯一目的是处理对象之间传递,使他们能够住对方的无知消息。

总的想法是这样的。 在提供通知视图模型你可能会做这样的事情:

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

而在有兴趣你可以做这样的事情该事件的视图模型:

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

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

请注意,这两个永远的ViewModels相互引用。 他们现在松耦合。

目前已经有一些预先存在的实现,这是不难创建自己的(信使基本保持有兴趣在一定的消息,并遍历时,它需要通知有关方面列表对象的列表) 。 有迹象表明,可以以不同的方式实现了一些东西(一些实现只是通过串绕的消息,而不是封装在对象的信息,以及一些自动处理观察员的清理)。

我会建议使用约什-史密斯(优秀) MVVM基金会 ,其中包括一种信使类。 这也是开源的,所以你可以看到它是如何工作的。



Answer 2:

关于什么没有明确的约束PropertyName应当包含PropertyChangedEventArgs 。

见订阅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"


Answer 3:

在这里做的最好的事情是分离模型和一个ViewModel的想法。

由于具有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);


文章来源: MVVM and INotifyPropertyChanged Issue
标签: c# wpf mvvm