我有一个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,我想赶上他们我的视图模型内。 我怎样才能做到这一点?
在我看来,有一些概念性的东西错了,你是问。 试想一下,你会得到您的方案作品(你是满意)的解决方案,并考虑以下因素:
- 如果添加了另一个层会发生什么? 你还期望它的工作一样吗?
- 如果属性更改传播(
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基金会 ,其中包括一种信使类。 这也是开源的,所以你可以看到它是如何工作的。
关于什么没有明确的约束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"
在这里做的最好的事情是分离模型和一个ViewModel的想法。
由于具有ViewModel
对象,它是不是平坦的Model
就可以避免这种情况。 使用自动映射工具,像Automapper然后允许你映射Model
到ViewModel
,反之亦然。
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);