当实体模型在视图模型中更改时更新 UI

本文关键字:更新 UI 实体模型 视图 模型 | 更新日期: 2023-09-27 18:31:38

我正在尝试想出一种使用实体框架实现MVVM模式的好方法,其中我的实体是我的模型。我的DataContext就是我的视图模型。这是问题的一个小再现。

视图

<TextBox Text="{Binding MyText}" />

视图模型

我需要从我的数据库中逐条记录地导航。在"视图"中单击按钮时,会将命令发送到执行nextRecord()的视图模型。EF 发挥其魔力,_myObject是数据库中的下一行/记录

public class myViewModel: INotifyPropertyChanged
{
    private MyEntityObject _myObject;
    public string MyText
    {
        get { return _myObject.MyText; }
        set
        {
            if (_myObject.MyText != value)
            {
                _myObject.MyText = value;
                OnPropertyChanged("MyText");
            }
        }
    }
    private void _nextRecord()
    {
      _myObject = myEntitiesContext.NextRecord() //pseudocode
    }
}

自动生成的实体模型

public partial class MyEntityObject
{
     public string MyText { get; set; }
}

由于视图不知道_myObject更改,因此_myObject更改时不会更新。我想到了几种方法。

  1. 我还没有测试过将我的实体包装在 INotifyPropertyChanged 包装器类中,但我对此持谨慎态度,因为我有很多实体对象。

  2. 我可以为所有属性调用OnPropertyChanged("..."),但我的一些实体有很多属性,这会很丑陋。可以使用反射来使其更干净,但我可能具有未绑定数据的属性。

  3. 我也许能够将其推迟到 UI,当我单击"下一条记录"时以某种方式刷新绑定,但这会破坏 MVVM 并且看起来很脏

如何让 UI 识别来自_myObject的更改?

当实体模型在视图模型中更改时更新 UI

正如我在注释中提到的,调用 OnPropertyChanged("")OnPropertyChanged(null) 会使所有属性无效,等效于为每个属性调用OnPropertyChanged。此处还记录了此行为:

事件可以指示对象上的所有属性 已通过使用 null 或 String.Empty 作为属性名称进行了更改 在 PropertyChangedEventArgs 中。

这意味着,只需在更新对象时添加对OnPropertyChanged("")的调用,以强制 WPF 重新评估视图模型的所有绑定:

private void _nextRecord()
{
    _myObject = myEntitiesContext.NextRecord();
    OnPropertyChanged("");
}

话虽如此,我仍然会使用 @Anand 的解决方案(+1)。关于视图模型是否可以将模型公开为属性,一直存在争论,我倾向于公开它,直到您需要引入一些特定于视图模型的逻辑。大多数情况下,您不必这样做,并且不值得麻烦包装模型属性。

代码的问题在于,当_myObject更改时,不会触发MyText属性更改事件。解决方法是创建一个新属性来保存您的实体并将此属性设置为视图中Grid 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>

一个非常简单但不是很优雅的解决方案,我相信可以满足需求:切换记录时,将 DataContext 设置为 null,然后返回到 ViewModel。

但是,可以说有更优雅的替代方案,需要更多的工作才能满足所有要求。请参阅阿南德的回答以对此进行改进。

View 中的标记应具有使用值设置的模式和 UpdateSourceTrigger 属性。