4

I am trying to come up with a good way of implementing the MVVM pattern using Entity-Framework where my entities are my models. My DataContext is my viewmodel. This is a small reproduction of the problem.

View

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

ViewModel:

I have the requirement of needing to navigate record by record from my DB. When a button is clicked in the View a command is sent to the Viewmodel that executes nextRecord(). EF does its magic and _myObject is the next row/record from the database

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
    }
}

Autogenerated Entity Model

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

Since the View has no knowledge of _myObject changing, it doesn't update when _myObject changes. A few approaches I have thought of.

  1. I haven't tested wrapping my entities in a INotifyPropertyChanged wrapper class but am wary to do this as I have a lot of entity objects.

  2. I could call OnPropertyChanged("...") for all properties, but some of my entities have a lot of properties to them, which would be ugly. Possible to use reflection to make it cleaner, but I may have properties that aren't databound.

  3. I might be able to defer this to the UI, somehow refreshing the bindings when I click "Next Record", but this breaks MVVM and looks dirty

How can I get the UI to recognize changes from _myObject?

4

4 回答 4

5

正如我在评论中提到的,调用OnPropertyChanged("")OnPropertyChanged(null)使所有属性无效,相当于调用OnPropertyChanged每个属性。此处也记录了此行为:

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

这意味着您可以OnPropertyChanged("")在更新对象时简单地添加一个调用,以强制 WPF 重新评估与您的视图模型的所有绑定:

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

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

于 2013-09-18T21:00:27.633 回答
3

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

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

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

于 2013-09-18T20:08:26.953 回答
-1

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

于 2013-09-18T08:39:35.173 回答