我的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支持。这是合理的还是不合理的?还有其他建议吗?
谢谢!
选项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
....