C# 在ViewModel中更改实体模型时更新UI
我正试图找到一种使用实体框架实现MVVM模式的好方法,其中我的实体就是我的模型。MyC# 在ViewModel中更改实体模型时更新UI,c#,wpf,entity-framework,mvvm,data-binding,C#,Wpf,Entity Framework,Mvvm,Data Binding,我正试图找到一种使用实体框架实现MVVM模式的好方法,其中我的实体就是我的模型。MyDataContext是我的viewmodel。这是问题的一个小复制品 查看 <TextBox Text="{Binding MyText}" /> 自动生成的实体模型 public partial class MyEntityObject { public string MyText { get; set; } } 由于视图不知道\u myObject的更改,因此当\u myObjec
DataContext
是我的viewmodel。这是问题的一个小复制品
查看
<TextBox Text="{Binding MyText}" />
自动生成的实体模型
public partial class MyEntityObject
{
public string MyText { get; set; }
}
由于视图不知道\u myObject
的更改,因此当\u myObject
更改时,它不会更新。我想到了一些方法
INotifyPropertyChanged
包装类中测试过如何包装实体,但是我很谨慎,因为我有很多实体对象OnPropertyChanged(“…”)
,但是我的一些实体有很多属性,这很难看。可以使用反射使其更干净,但我可能有未进行数据绑定的属性如何让UI识别来自
\u myObject
的更改?代码的问题是当\u myObject
更改时,MyText
属性更改事件不会触发。一个解决办法是创建一个新的属性来保存您的实体
并将此属性作为视图中的网格
sDataContext
,如下所示。现在,当执行这一行时,MyObject=myEntitiesObject.NextRecord()
您的视图将收到有关更改的通知
public class myViewModel : INotifyPropertyChanged
{
private MyEntityObject _myObject;
public MyEntityObject MyObject
{
get { return _myObject; }
set {
if (_myObject != value)
{
_myObject = value;
OnPropertyChanged("MyObject");
}
}
}
private void _nextRecord()
{
MyObject = myEntitiesObject.NextRecord() //pseudocode
}
}
查看:
<Grid DataContext="{Binding MyObject}">
<TextBlock Text="{Binding MyText}"/>
</Grid>
视图中的标记应使用值设置mode和UpdateSourceTrigger属性 我认为这是一个非常简单但不是很优雅的解决方案,可以满足需要:在切换记录时,将DataContext设置为null,然后返回ViewModel
然而,可以说还有更优雅的替代方案需要更多的工作来满足所有的需求。请参阅Anand的答案以了解对此的改进。正如我在评论中提到的,调用
OnPropertyChanged(“”
或OnPropertyChanged(null)
将使所有属性无效,相当于为每个属性调用OnPropertyChanged
。这种行为也是:
PropertyChanged事件可以指示对象上的所有属性
已使用null或String.Empty作为属性名进行更改
在PropertyChangedEventArgs中
这意味着您可以在更新对象以强制WPF重新评估视图模型的所有绑定时,简单地添加对OnPropertyChanged(“”)的调用:
private void _nextRecord()
{
_myObject = myEntitiesContext.NextRecord();
OnPropertyChanged("");
}
话虽如此,我仍然支持@Anand的解决方案(+1)。关于viewmodel是否可以将模型作为属性公开存在一个持续的争论,我倾向于公开它,直到需要引入一些特定于视图模型的逻辑。大多数情况下,您不必这样做,也不值得费心包装模型属性。这不会解决任何问题。问题与从视图更新ViewModel无关,相反,问题在于它使ViewModel绑定无效
MyText
现在将绑定到我的模型而不是ViewModel,这意味着整个ViewModel实际上没有任何用途。另一个问题是,除非我将实体对象包装到另一个类中以处理INotifyPropertyChanged
,MyText
将无法响应更改,因为现在绑定在模型上,而不是viewmodel@Shoe,您的ViewModel应该仍然有一个用途--它保存命令,执行初始化和其他操作。此外,如果您确实希望在DataContext发生更改后绑定到ViewModel,则只需相对地将绑定到视图的DataContext即可。唯一的问题是我们看不到从UI外部对实体进行的更新,但如果您的模型只是一堆普通的旧属性,这是意料之中的。@Guttsy视图模型应该是模型的一个接口。从视图到模型的绑定直接意味着我们绕过了任何过滤/操作数据的方法。假设我想验证用户输入到视图中的数据。现在很难做到这一点,因为绑定绕过了我的业务层。那么,业务规则和验证应该在适当的(可重用的)类(如业务对象)中实现,业务对象可以理解如何通知属性已更改。仅将实体用作进出数据库的接口。如果您打算在ViewModel中完成所有这些,那么您可能并不是真正在做MVVM,您希望您的应用程序不会变大。@Guttsy抱歉,我不一定指业务逻辑,而只是验证通过它获得的数据。让VM负责这一点是可以的,但是直接绑定到模型意味着您无法验证。此时唯一的解决方法是在视图和模型之间创建一个包装类或另一层。从_nextRecord()中手动调用OnPropertyChanged如何?@WiktornextRecord
不是真正的方法,我只是想隐藏获取下一条记录的实现细节,因为它们对问题并不重要。但你说的基本上是我的第二种方法。问题是,它不能扩展到15-20个属性,您需要调用OnPropertyChanged
15-20次,那又怎样?这就是实际发生的情况,一个对象被另一个对象替换,这意味着20个属性发生更改,因此20个ui组件需要刷新。绑定背后没有魔法,如果某个地方没有人触发更新,什么也不会发生。@Wiktor我不关心性能。看到20个电话真难看
private void _nextRecord()
{
_myObject = myEntitiesContext.NextRecord();
OnPropertyChanged("");
}