C# 使用EF和MVVM从UI截取属性更新的更好方法

C# 使用EF和MVVM从UI截取属性更新的更好方法,c#,.net,wpf,entity-framework,mvvm,C#,.net,Wpf,Entity Framework,Mvvm,我有一个具有撤销重做功能的WPF应用程序。我使用EF与数据库交互 我想知道,当UI更改某些属性时,是否有更好的方法或模式可以得到通知 以下是我目前使用的方法: 让EF生成类。例如: public partial class Page: IObjectWithChangeTracker, INotifyPropertyChanged { #region Primitive Properties [DataMember] public string title { get { retur

我有一个具有撤销重做功能的WPF应用程序。我使用EF与数据库交互

我想知道,当UI更改某些属性时,是否有更好的方法或模式可以得到通知

以下是我目前使用的方法:

  • 让EF生成类。例如:

    public partial class Page: IObjectWithChangeTracker, INotifyPropertyChanged
    {
    #region Primitive Properties
    
    [DataMember]
    public string title
    {
        get { return _title; }
        set
        {
            if (_title != value)
            {
                _title = value;
                OnPropertyChanged("title");
            }
        }
    }
    private string _title;
    
    ...
    
  • 然后在类的非生成部分,我为UI添加了另一个属性。在这种特殊情况下,属性绑定到WPF文本框:

    public partial class Page
    {
    public Page()
    {
        ((INotifyPropertyChanged)this).PropertyChanged += Page_PropertyChanged;
    }
    
    void Page_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName) {
        case "title":
            OnPropertyChanged("titleUI");
            break;
        }
    }
    
    public string titleUI
    {
        get { return title; }
        set
        {
            if (value == title)
                return;
            string oldValue = title;
            title = value;
            UndoRedo.PushAtomic(
                () => title = oldValue, 
                () => title = value,
                "change page title");
        }
    }
    
    ...
    
我曾经听过FrameworkElement.SourceUpdated,但我放弃了这种方法,更密切地遵循MVVM设计模式

有更好或更简单的方法吗

编辑:我没有将文本框直接绑定到
title
属性的原因是,我不想在属性被文本框以外的其他内容更新时添加到撤消重做堆栈中。此外,当EF ObjectContext具体化实体时,值由setter分配,我也不想将其添加到undo-redo堆栈中


编辑2:对于这个问题,我有点放弃了SO。如果可以,我会删除它。例如,我无法理解关于我的代码不是真正的MVVM的评论与手头的问题有什么关系。无论我是否将实体类与所谓的ViewModel类严格分开,我仍然必须找到一种从UI“截取”更新的方法。我投票决定结束。如果你觉得这是行不通的,请你也这么做。

这不是你想要的答案,但我想看看Unity:

这是一个silverlight post(但它也适用于WPF等)。基本上,您可以为您的模型创建一个拦截器,并将代码注入属性getter/setter。这样,您就可以调用N级撤消/重做处理代码,而无需重新实现属性

但是,您所做的看起来更像是一个富模型,而不是一个viewmodel,因为标准的viewmodel将封装该模型

我不想为模型上的每个属性编写额外的属性getter/setter代码

(他们展示了一个虚拟方法拦截器,但也可以使用实例拦截器,我认为这是可行的,但请听一下他们关于拦截器的观点以及他们“侦听”的范围)

编辑:

很抱歉没有真正回答这个问题

以下是一些建议:

我不确定EF是否让您的实体类派生自基类,但这是一件需要考虑的事情——您只需在基类中钩住PropertyChanged事件并进行相应的处理。您可以在底座上保留一个
字典
,以跟踪“旧”值并处理撤消操作

我理解EF具体化对象的一点-您不能在UndoRedo堆栈上添加一个标志,告诉它在对象具体化时忽略任何属性更改吗


必须有一些方法可以在部分实体类中重写,以告诉堆栈绕过任何撤消/重做信息。wpf textbox有一个内置的撤消/重做-因此,如果您只是将viewmodel属性绑定为mode=twoway,那么您的viewmodel和视图总是同步的,并且您的textbox处理重做撤消。我错过了什么吗?

这里似乎有一个奇怪的方法-我的观点是正确的,你有一个混合模型/视图模型吗?看起来Page是您的模型,但您只是通过使用partial来扩展Page类作为ViewModel?是的,ViewModel将是生成的类(即模型)的“扩展”。好的,从技术上讲,我不会将其称为ViewModel—它更像一个富模型—有什么原因不能绑定到Title属性吗?既然你正在制作一个丰富的模型,你也可以使用它的属性。这就是我在MVVM中遇到的问题——事实上,你最终在VM中重新实现了所有东西。有一些框架为您提供了一个丰富的(生成的)模型,然后允许您通过VM公开这个模型。通过这种方式,您可以绑定到模型上的属性,而不是在viewmodel中重新实现它们。在您的情况下,可能值得使用Unity/Ninject之类的工具来钩住属性更改事件——这样您就可以将代码注入到生成的代码中,而无需重新实现所有内容。我不喜欢这个代码的外观,它会给我一个headache@Charleh:我必须问:为什么不能将类的文件分离视为模型/视图模型分离?你的这一断言是基于什么?不确定-我自己没有使用MEF,但快速的谷歌搜索并没有带来任何有趣的结果。我唯一能找到的是:它说MEF完全没有拦截功能(但这是从2011年3月开始的)我的回答的缺点是,当您从文本框以外的任何位置设置属性时,会删除重做/撤消堆栈。