Wpf 用于集合的MVVM

Wpf 用于集合的MVVM,wpf,mvvm,Wpf,Mvvm,我最近开始学习wpf,并尝试使用mvvm 我的理解是,在mvvm中,视图和模型都不应该知道另一个存在 我想做的是在屏幕上显示客户列表。但是如果我对viewModel编码如下所示。这类似于我在网上看到的许多例子,然后我得到了一些类似这样的代码 class客户 { 公共字符串名称{get;set;} 公共字符串地址{get;set;} } 类MainWindowViewModel { ObservableCollection客户=新ObservableCollection(); 公共可观测收

我最近开始学习wpf,并尝试使用mvvm

我的理解是,在mvvm中,视图和模型都不应该知道另一个存在

我想做的是在屏幕上显示客户列表。但是如果我对viewModel编码如下所示。这类似于我在网上看到的许多例子,然后我得到了一些类似这样的代码

class客户
{    
公共字符串名称{get;set;}
公共字符串地址{get;set;}
}
类MainWindowViewModel
{
ObservableCollection客户=新ObservableCollection();
公共可观测收集客户
{
获取{返回客户;}
} 
公共主窗口视图模型()
{
//cust1和cust2是客户对象
添加(cust1);
添加(cust2);
}
}
现在,如果我创建了我的MainWindowViewModel的一个实例,并将其设置为我的MainWindowView(我的视图)的datacontext,并且我进一步将viewmodelsCustomers属性绑定到一个列表框,那么视图将需要对包含我的模型的程序集的引用

所以我的问题是

1) 添加对MVVM中允许的模型程序集的引用,因为这意味着视图知道该模型

2) 更好的解决方案是将每个Customer对象包装在CustomerServiceWModel中,并让MainWindowViewModel包含CustomerServiceWModel的可见集合
而不是可观察到的客户收集。这将使模型与视图完全分离。

我们通常创建CustomServiceWModel。这是由我们的通用CollectionViewModelBase类强制实现的。这表明用户界面使用的每个部分都是专门创建来显示的,我们在模型中没有任何与UI相关的代码,这些代码通常是可序列化的POCO

  • 我不知道您为什么认为包含视图的项目需要引用模型项目?视图中没有直接引用模型的内容-XAML中的绑定表达式仅按名称链接,并且链接到视图模型上的属性,而不是模型
  • 如果视图需要比模型提供的数据更多的数据,并且不希望更改模型,则在视图模型中包装模型是一个不错的选择。例如,视图可能需要显示
    用户
    类型的
    年龄
    ,但
    用户
    只有
    出生日期
    属性。如果您不想更改模型,那么使用
    Age
    属性创建
    UserViewModel
    将是一个不错的选择
    MVVM模式与任何其他MVx模式(MVC、MVP等)相似,因为它鼓励关注点分离(SoC),从而提高代码的可维护性/可测试性。除了通常的SoC之外,MVVM还提供以下功能:

    Model <= View
    
  • 视图逻辑的单元测试;这是因为您将逻辑从视图移动到视图模型中,从而使视图尽可能愚蠢
  • 开发者-设计者工作流程;因为视图是“哑的”,所以在没有背后逻辑的情况下使用XAML更容易
  • 关于可见性,即什么对什么可见,严格如下:

    Model <= ViewModel <= View
    

    Model您肯定希望将模型包装在仅查看的对象中,如下所示:

    /// <summary>
    /// Business model object : Should be in your separate business model only library
    /// </summary>
    public class BusinessModelObject
    {
        public string Prop1 { get; set; }
        public int Prop2 { get; set; }
    }
    
    
    
    /// <summary>
    /// Base notifying object : Should be in your GUI library
    /// </summary>
    public abstract class NotifyingObject<T> : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public void NotifyPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, e);
        }
    
    
        private static readonly PropertyChangedEventArgs ModelPropertyChanged = new PropertyChangedEventArgs("Model");
        private T _model;
        public T Model
        {
            get { return _model; }
            set
            {
                _model = value;
                NotifyPropertyChanged(ModelPropertyChanged);
            }
        }
    }
    
    /// <summary>
    /// Model decorator : Should be in your GUI library
    /// </summary>
    public class BusinessModelObjectAdapter : NotifyingObject<BusinessModelObject>
    {
        public BusinessModelObjectAdapter(BusinessModelObject model)
        {
            this.Model = Model;
        }
    
        private static readonly PropertyChangedEventArgs Prop1PropertyChanged = new PropertyChangedEventArgs("Prop1");
        private string _prop1;
        public string Prop1
        {
            get { return Model.Prop1; }
            set
            {
                Model.Prop1 = value;
                NotifyPropertyChanged(Prop1PropertyChanged);
            }
        }
    
        private static readonly PropertyChangedEventArgs Prop2PropertyChanged = new PropertyChangedEventArgs("Prop2");
        private int _prop2;
        public int Prop2
        {
            get { return Model.Prop2; }
            set
            {
                Model.Prop2 = value;
                NotifyPropertyChanged(Prop1PropertyChanged);
            }
        }
    
        //and here you can add whatever property aimed a presenting your model without altering it at any time
    }
    
    //
    ///业务模型对象:应位于单独的仅限业务模型库中
    /// 
    公共类BusinessModelObject
    {
    公共字符串Prop1{get;set;}
    公共int Prop2{get;set;}
    }
    /// 
    ///基本通知对象:应位于GUI库中
    /// 
    公共抽象类NotifyingObject:INotifyPropertyChanged
    {
    公共事件属性更改事件处理程序属性更改;
    public void NotifyPropertyChanged(PropertyChangedEventArgs e)
    {
    PropertyChangedEventHandler处理程序=PropertyChanged;
    if(handler!=null)handler(this,e);
    }
    私有静态只读PropertyChangedEventArgs ModelPropertyChanged=新PropertyChangedEventArgs(“模型”);
    私有T_模型;
    公共T模型
    {
    获取{return\u model;}
    设置
    {
    _模型=价值;
    NotifyPropertyChanged(ModelPropertyChanged);
    }
    }
    }
    /// 
    ///模型装饰器:应该在您的GUI库中
    /// 
    公共类BusinessModelObjectAdapter:NotifyingObject
    {
    公共BusinessModelObjectAdapter(BusinessModelObject模型)
    {
    这个模型=模型;
    }
    私有静态只读属性ChangedEventArgs Prop1PropertyChanged=新属性ChangedEventArgs(“Prop1”);
    私有字符串_prop1;
    公共字符串Prop1
    {
    获取{return Model.Prop1;}
    设置
    {
    Model.Prop1=值;
    NotifyPropertyChanged(Prop1PropertyChanged);
    }
    }
    私有静态只读属性ChangedEventArgs Prop2PropertyChanged=新属性ChangedEventArgs(“Prop2”);
    私人内部程序2;
    公共int Prop2
    {
    获取{return Model.Prop2;}
    设置
    {
    Model.Prop2=值;
    NotifyPropertyChanged(Prop1PropertyChanged);
    }
    }
    //在这里,您可以添加任何属性来演示您的模型,而无需在任何时候对其进行更改
    }
    
    回答您的问题:

  • 引用模型的视图有什么不好?当它简化代码时,这是绝对正确的。另一种方法(模型->视图)是不好的做法

  • 当您没有特殊需求时,不需要将每个客户对象包装在CustomerServiceWModel中。我建议遵循一种务实的方式,并保持代码简单


  • 您可能对BookLibrary示例应用程序感兴趣,该应用程序显示了您在此处描述的场景。

    当我通过代码隐藏将视图的DataContext设置为viewModel时