Entity Framework CTP5 Code First,WPF - MVVM建模

5

我已经为我的WPF应用程序设置好了模型,并使用实体框架ctp5代码优先方式进行工作,以下是一个示例模型类:

public class Task
{
    public int ID { get; set; }
    public int Index { get; set; }
    public string Content { get; set; }
    public int Indentation { get; set; }
    public DateTime Start { get; set; }
    public decimal Effort { get; set; }
    public decimal CompletedEffort { get; set; }
    public decimal Cost { get; set; }
}

什么是构建视图模型的推荐方式?我的视图模型将实现INotifyPropertyChanged,我不希望模型类具有任何UI特定代码,以便它们可以轻松地在其他应用程序中重用。我应该使所有模型属性都为虚拟的,然后在视图模型中重写它们吗?(似乎编码过多且不必要...)EF Code First能够与这种格式很好地配合吗?
编辑 这是一个类似的问题 In MVVM should the ViewModel or Model implement INotifyPropertyChanged?,然而,唯一的解决方案似乎是将我认为是UI逻辑添加到模型中。也许我可以向模型添加某种委托,并从视图模型中挂钩,后者将反过来使用INotifyPropertyChanged...类似于这样的东西?
    public class Task
    {
        public delegate void HandleChange(string propertyName);
        public HandleChange ChangeHandler;

        public int ID 
        { 
            get
            {
                return ID;
            } 
            set
            {
                if(ID != value)
                {
                    ID = value;
                    ChangeHandler("ID");
                }
            }
        }
...

4
Chris,你的代码实际上是 INotifyPropertyChanged 接口的一种实现!你的委托 HandleChange 的目的与 PropertyChangedEventHandler 委托相同,变量 ChangeHandler 的作用与 PropertyChanged 相同。唯一的区别在于你没有将 ChangeHandler 标记为 event(这只是一个保护机制,允许仅订阅和取消订阅,但禁止例如将处理程序设置为空)。顺便说一下:INotifyPropertyChangedSystem.dll 程序集、System.ComponentModel 命名空间中,与 WPF 或 UI 完全无关。 - Slauma
2个回答

4

我正在做的是将我的模型类实例化为ViewModel中的一个属性,然后直接在模型上实现INotifyPropertyChanged,以便于对模型属性进行通知,而在ViewModel中只对模型实例实现INotifyPropertyChanged

public class Task : INotifyPropertyChanged
{
    // Implementation of INotifyPropertyChanged
    // Raising the PropertyChanged event in the Setters of all properties
}

public class TaskViewModel : INotifyPropertyChanged
{
    private Task _task;
    public Task Task
    {
        get
        {
            return _task;
        }
        set
        {
            if (_task != value)
            {
                _task = value;
                RaisePropertyChanged("Task");
            }
        }
    }

    // INotifyPropertyChanged implementation
}

然后在XAML中,我直接绑定到模型属性,例如:

<TextBox Text="{Binding Task.Content}" />

(TaskViewModel将成为此视图的DataContext。)

我这样做主要是为了避免你提到的“大量不必要的编码”,而且我找不到任何缺点。(我也用EF Code-First使我的模型持久化。)


在这种特定情况下,这可能是一个有效的解决方案,但通常你没有模型的代码,因此无法实现 INotifyPropertyChanged... - Thomas Levesque
3
@Chris:1) INotifyPropertyChanged 只包含一个通用的 .NET 事件,可以使对象的更改能够从外部观察到。我可以在任何上下文中订阅它,不仅限于 WPF/MVVM。这个事件在其他项目中也可以使用。如果我不需要它,我就不会订阅它。模型属性的更改是模型的关注点,因此我不认为违反了关注点分离原则。2)当然 ViewModel 不仅只有一个 Model 实例,例如绑定到 UI 操作的 Commands 等确实不属于 Model...(续) - Slauma
继续...或其他UI特定属性,这些属性不能直接映射到模型属性。因此,为了处理所有这些,我仍然需要一个ViewModel。尽管如此,我可以理解您不喜欢这个解决方案,我之前也不喜欢它。但是我找不到另一种方法,要么就是按属性复制所有模型属性到ViewModel并在Model和ViewModel属性之间进行映射。我的模型类现在更加臃肿(它们还实现了IDataErrorInfo),但与WPF无关。 - Slauma
@Chris:如果你能找到这个解决方案之外的另一种方法,并且不需要将所有属性复制到ViewModel中,能否在这里加上一个简短的注释?我也会非常感兴趣的 ;) - Slauma
@Slauma - 这似乎是一个不错的开始 https://dev59.com/93RA5IYBdhLWcg3w8ikl - Chris Klepeis
显示剩余3条评论

3
我知道这是一个老帖子,但我正在搜索这个主题并偶然发现了blogs.msdn.com的文章:http://bit.ly/iE3KHI 简而言之,在EF CodeFirst的CTP 4中,CodeFirst dbSet对象有一个新属性.Local。.Local是一个实现INotifyPropertyChanged的ObservableCollection。因此,如果您有一个公开了名为Tasks的DbSet(Of Task)的Code First DbContext,您可以将您的表单数据上下文设置为Tasks.Local。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接