C# 在ViewModel中更改实体模型时更新UI

C# 在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

我正试图找到一种使用实体框架实现MVVM模式的好方法,其中我的实体就是我的模型。My
DataContext
是我的viewmodel。这是问题的一个小复制品

查看

<TextBox Text="{Binding MyText}" />
自动生成的实体模型

public partial class MyEntityObject
{
     public string MyText { get; set; }
}
由于视图不知道
\u myObject
的更改,因此当
\u myObject
更改时,它不会更新。我想到了一些方法

  • 我还没有在
    INotifyPropertyChanged
    包装类中测试过如何包装实体,但是我很谨慎,因为我有很多实体对象

  • 我可以为所有属性调用
    OnPropertyChanged(“…”)
    ,但是我的一些实体有很多属性,这很难看。可以使用反射使其更干净,但我可能有未进行数据绑定的属性

  • 我可能可以将此延迟到UI,在单击“下一条记录”时以某种方式刷新绑定,但这会破坏MVVM并看起来很脏


  • 如何让UI识别来自
    \u myObject
    的更改?
    代码的问题是当
    \u myObject
    更改时,
    MyText
    属性更改事件不会触发。一个解决办法是创建一个新的属性来保存您的实体 并将此属性作为视图中的
    网格
    s
    DataContext
    ,如下所示。现在,当执行这一行时,
    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如何?@Wiktor
    nextRecord
    不是真正的方法,我只是想隐藏获取下一条记录的实现细节,因为它们对问题并不重要。但你说的基本上是我的第二种方法。问题是,它不能扩展到15-20个属性,您需要调用
    OnPropertyChanged
    15-20次,那又怎样?这就是实际发生的情况,一个对象被另一个对象替换,这意味着20个属性发生更改,因此20个ui组件需要刷新。绑定背后没有魔法,如果某个地方没有人触发更新,什么也不会发生。@Wiktor我不关心性能。看到20个电话真难看
    private void _nextRecord()
    {
        _myObject = myEntitiesContext.NextRecord();
        OnPropertyChanged("");
    }