M-V-VM:处理从XmlSerialized数据动态生成的模型数据的最佳方法是什么

时间:2013-03-28 11:03:02

标签: c# mvvm observablecollection inotifypropertychanged xmlserializer

我有两个实际的用户生成数据和依赖它的数据(比如UniformGrid单元格的背景颜色,用于表示网格中的重写值,每次从网格的ObservableCollection中触发INotifyPropertyChanged时计算)。在模型中还有其他这样的对象是相互依赖的。现在,当反序列化时,根据模型类中对象的顺序,某些依赖对象会正确更新,而某些则不会。 (我来自MFC编程,用于在加载文件后调用UpdateData()并立即设置所有DDX控件。)

整个事情很容易在后续的代码更改中出错,并且感觉非常笨拙。就像WPF的很多东西一样:如果你想完成一项简单的任务,那么它很快就会完成。如果你想要特定的东西,它会变得比它应该复杂得多。如何处理这个问题有什么好的做法吗?

1 个答案:

答案 0 :(得分:1)

似乎您的主要问题是正确的关注点分离。 WPF& MVVM与更传统的Windows开发方法完全不同。

首先,让我们在这里找到一些东西 - 它可能只是与术语混淆,但我会提到它。

在MVVM中,模型不用于存储数据。

可以用于保存数据吗?是。 应该用于保存数据吗?没有。

保存和转换数据是viewmodel的工作。模型的工作是充当管道,它获取数据(即从存储库中检索,或控制与WCF服务的通信等)。如果您的模型持有数据意味着您的视图将绑定到模型,这是错误的。

您所谈论的部分数据也应保存在视图中。确定某些内容是否重复可以在viewmodel中确定,甚至可能在模型中确定(模型可以应用业务规则并在数据通过时标记数据)。要为副本显示的颜色是视图责任 - 除非该颜色由业务规则确定,然后您可以将其移动到视图模型。

您绑定到ObservableCollection,它推断您正在使用像DataGrid一样的转发器类型控件。在这种情况下,每一行都不知道任何其他行。如果从一行的数据对象触发属性更改事件,则另一行将完全不知道它,因此无法根据这些更改更改其呈现方式。在这种情况下,您必须以观察者模式方式调整相关行的数据。

当你有这样的相互依赖关系时,将每个实际数据对象包装在另一个充当外观的轻量级对象中是正常的,有些人将其称为每个行的数据对象都有一个viewmodel。例如,这是一个简单的Customer对象:

public class Customer
{
    public string FirstName {get; set;}

    public string Surname {get; set;}
}

当你将它存储在viewmodel的ObservableCollection中时,你可以将它包装起来:

public class CustomerWrapper
{
    private Customer _customer;
    public CustomerWrapper (Customer customer)
    {
        _customer = customer;
    }

    public bool HasRelation{get;set;}

    public Customer Customer { get {return _customer;}}
}

现在,如果要指示Customer对象之间的相互依赖关系,例如,如果它们属于一个系列,则只需在创建CustomerWrapper对象后设置HasRelation属性:

var myCustomerList = GetMyCustomers();
foreach (var customer in myCustomerList)
{
    myObservableCollection.Add(new CustomerWrapper(customer) 
    { 
        HasRelation = myCustomerList.Where(p => string.Equals(p.Surname, customer.Surname).Count() > 1) 
    }); 
}

现在,当您将转发器控件绑定到ObservableCollection时,您可以使用HasRelation属性来控制UI颜色等。

请记住,我保留这是一个人为的例子,我保持简单,我故意错过了一些东西,以保持简短。如果您的viewmodel订阅了每个Customer对象的属性更改事件,则可以根据需要更新CustomerWrapper对象。相互依赖状态不需要与存储库中的数据一起存储,因为您可以在每次显示数据时确定它。我省略的一件事是包装FirstName和Surname proeprties - 你可以为它们添加一个包装器属性,或者你可以简单地使用XAML绑定中的路径向下钻取到嵌套对象。