正在将INotifyPropertyChanged添加到模型

本文关键字:模型 添加 INotifyPropertyChanged | 更新日期: 2023-09-27 17:59:30

我的wpf MVVM(基于Prism)应用程序面临一些设计问题,很乐意得到您的建议。我的模型很简单:

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

正如您所看到的,我的Model类没有任何INotifyPropertyChnaged支持。我还有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更新,而Model本身不支持INotifyPropertyChanged,因此不会调用Item setter,并且IsDirty保持为false(因此不会更新UI上的IsDirty通知)。

我知道我可以在模型中支持INotifyPropertyChanged,然后在视图模型中注册Item.PropertyChanged事件,并实际将IsDirty设置为true,但是-由于我也使用CodeFirst,并且我的Model类在我的ServerSide和客户端之间共享(不使用添加服务引用),所以我不想将INotifyPreoprtyChanged内容添加到我的服务器端。

我正在考虑创建一个新项目,该项目将使用T4模板逐个复制我的所有实体(作为客户),并为每个模型添加INotifyPropertyChanged支持。这是合理的还是不合理的?还有其他建议吗?

谢谢!

正在将INotifyPropertyChanged添加到模型

选项1。
将在客户端和服务器(DTO)之间传输的实体与作为客户端模型的实体分开。在模型中实现INPC。使用这些实体之间的映射。

选项2.
仅将视图绑定到视图模型属性。生成视图模型属性,该属性包裹相应的模型属性。

选项3.
是前两个选项的混合。不要在视图模型中聚合模型。使用模型和视图模型之间的映射。使视图具有与模型特性相对应的模型特性。

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


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的精神。

如果您希望UI在模型属性发生更改时注意到,则模型类必须实现INotifyPropertyChanged和类似的MVVM接口(IDataErrorInfo等),以便将Notify连接到property changed所在的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,将backing fields创建为properties,对于每个属性setter,在set操作之后,使用property名称引发OnPropertyChanged调用的方法。

如果你不喜欢用INotifyPropertyChanged代码扰乱你的模型,你可以尝试使用一个名为PropertyChanged.Fody 的NUGet包

你可以这样使用它;

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

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

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

您可以在客户端项目中添加一些构建符号,例如"WPF";并且在代码优先定义中,只有当存在"WPF"构建符号时才实现CCD_ 16。然后,只需将服务器端域类添加为演示应用程序的链接即可。类似于;

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