将INotifyPropertyChanged添加到模型中?

7

我在我的WPF MVVM(基于Prism)应用中遇到了一些设计问题,希望能得到您的建议。 我的模型非常简单:

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

正如您所看到的,我的模型类没有任何支持INotifyPropertyChanged的功能。我还拥有一个 CustomerDetails 屏幕的 ViewModel,它支持 INotifyPropertyChanged。

public class CustomerDetailsViewModel:INotifyPropertyChanged /*Or NotificationObject*/
{
   /*INotifyPropertyChanged event */
   private Customer item;
   public Customer Item
   {
      get{return item;}
      set
      {
         item=value; 
         //Raise PropertyChanged
         //Set IsDirty to true
      }
   }
}

在我的看法中,我正在使用绑定到Item.FirstName并更新我的ViewModel。我的问题是,由于只有FirstName属性通过View进行更新,而模型本身不支持INotifyPropertyChanged,因此Item setter未被调用,IsDirty仍然等于false(因此不会在UI上更新IsDirty通知)。
我知道我可以在模型中支持INotifyPropertyChanged,然后在ViewModel中注册到Item.PropertyChanged事件,并将IsDirty实际设置为true。但是, 由于我还在使用CodeFirst,并且我的Model类在我的ServerSide和客户端之间共享(不使用Add Service Reference),我不想向我的ServerSide添加INotifyPreoprtyChanged内容。
我正在考虑创建一个新项目,使用T4模板逐个复制所有实体(如Customer)并为每个模型添加INotifyPropertyChanged支持。这是否合理?是否有其他建议?
谢谢!
5个回答

4
Option1.
将在客户端和服务器之间传输的实体(DTO)与客户端模型分开。在模型中实现INPC。使用这些实体之间的映射。
Option2.
仅将视图绑定到视图模型属性。使视图模型属性包装相应的模型属性。
Option3.
是前两个选项的混合。不要在视图模型中聚合模型。在模型和视图模型之间使用映射。创建与模型属性对应的视图模型属性。

1

你的方法并不是最好的。更好的方法是使用像这样的虚拟机。


public class CustomerDetailsViewModel : INotifyPropertyChanged
{
  public CustomerDetailsViewModel(Customer customer)
  {
    _item = customer;
  }
  private Customer _item;

  public string FirstName
  { 
    get { return _item != null ? _item.FirstName : null; }
    set 
    {
      if (_item == null)
        _item = new Customer(); // just an example, probably it's not the desired behavior
      _item.FirstName = value;
      RaisePropertyChanged(...);
    }
  }
  ...
}

这将遵循MVVM的精神。

3
我理解你的意思,但这将需要大量编码却没有太多必要。我应该在我的视图模型中复制每个模型属性吗? - Asaf
@Asaf 你说得对。我不了解你的项目。如果只是一个小项目,那么这可能会带来巨大的开销。但在更大的项目中,当你有额外的要求,比如可测试性、解耦等等,这可能是实现它们的一种方式。 - DHN

1
如果您希望UI注意到您的模型属性已更改,则您的模型类必须实现INotifyPropertyChanged和类似的MVVM接口(IDataErrorInfo等),以便向UI通知属性更改。
这是因为您并不总是从视图模型更新模型,在视图模型中必须实现INotifyProperyChanged并通知更改。
当您无法在模型类中实现INotifyPropertyChanged时,可以在视图模型中包装相应的模型属性,这会导致视图模型变得非常庞大,并创建不必要的代码重复。
例如,场景如下:
public class Customer
{
   public string FirstName {get;set;}
   public string LastName {get;set;}

   // Changes the first name.
   public void ChangeFirstName(string newName)
   {
      FirstName = newName;
      //The UI will never know that the property changed, and it won't update.
   }
}

解决方案:
在您的模型类中实现 INotifyPropertyChanged 接口,为您的 properties 创建 backing fields,并对于每个属性的 setter,在 set 操作之后,使用该属性的名称调用 OnPropertyChanged 方法。

0
如果您不喜欢在模型中添加INotifyPropertyChanged代码,您可以尝试使用一个名为PropertyChanged.Fody的NUGet包。
使用方法如下:
using PropertyChanged;

[ImplementPropertyChanged]
public class Customer
{
   public string FirstName {get;set;}
   public string LastName {get;set;}
}

此类中的任何公共属性现在都将支持INotifyPropertyChanged。


-1

我认为你走在了正确的道路上。在服务器端,你不需要使用INotifyPropertyChanged,因此不要将其添加到服务器端的域类中。

你可以只向客户端项目添加一些构建符号,例如“WPF”;并且在代码优先定义中仅在存在“WPF”构建符号时实现INotifyPropertyChanged。然后只需将服务器端的域类作为链接添加到演示应用程序中。就像这样:

#if WPF
public class MyEntity : INotifyPropertyChanged
#else
public class MyEntity

....

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接