我一直在使用C#中的MVVM应用程序,但是在使用ViewModels的集合时会遇到一些问题。具体而言,它们都倾向于与模型是ViewModel的私人成员有关。
一个例子是创建新的ViewModels(按视图的要求)。对于某些序言(尽管您可能不需要这些来帮助我),这是示例模型和ViewModel类:
Private Class Model()
{
public string Name { get; set; }
}
Public Class ViewModel()
{
Private Model _Model;
Public Void ViewModel(Model model)
{
_Model = model;
}
Public String Name
{
get
{
return _Model.Name;
}
set
{
_Model.Name = value;
}
}
}
整个模型永远不会直接作为ViewModel的公共成员暴露。MainWindowViewModel处理模型的集合(私有,视图看不见这些)和ViewModels(公共供查看消化):
Public Class MainWindowViewModel
{
Private List<Model> _NamesModel;
Private ObservableCollection<ViewModel> _NamesViewModel;
Public Void MainWindowViewModel()
{
//Lets pretend we have a service that returns a list of models
_NamesModel = Service.Request();
foreach(Model model in _NamesModel)
{
ViewModel viewmodel = new ViewModel(model);
_NamesViewModel.Add(viewmodel);
}
}
Public ObservableCollection<ViewModel> NamesViewModel
{
get
{
return _NamesViewModel;
}
}
}
现在,这是序言,但现在我有一个问题。如何添加新的ViewModel?我视图中的方法会创建新的ViewModel并填充它吗?作为纯粹主义者,我假设不应完全允许创建或填充模型。我的ViewModel是否应该包含一个不接受的构造函数(即没有基础模型),而是创建一个空白以填充?
这些问题不断提出"纯" MVVM方法。我必须在我的ViewModel(Bool比较(模型模型))中创建一个公共方法,该方法将将模型(准备删除等)与内部使用比较。如果这些模型是公开暴露的(断开纯度),那么做一些事情要容易得多,例如找到与模型连接的ViewModel。
我可以同情其中一些问题。我最近写了一个MVVM应用程序,其中经常出现类似的问题。诀窍之一是确定哪个类将负责模型实例。您是否希望它成为您的MainWindowViewModel?还是您的nameViewModel?您不想分享在这两个类之间创建/删除模型的职责;您将有一场后勤的噩梦。
其次,即使是"纯" MVVM方法,也不能规定您不能公开展示该模型。您说这样做会为您节省很多头痛:做到这一点。MVVM仅规定ViewModel没有视图的知识/访问。有许多"官方" MVVM示例,甚至使用InotifyPropertychanged接口实现其模型,并直接与模型上的属性结合。
就我个人而言,我认为我将控制名称ViewModel的Namemodel控制。这意味着您应该从MainWindowViewModel完全删除Namemodels的列表。如果您想将nameViewModel一个可选的构造函数提供模型,那也很好。
我是这种方法的粉丝:
public NameViewModel : ViewModelBase
{
public NameModel Model
{
get { /* get stuff */ }
set { /* set stuff */ }
}
// Default constructor creates its own new NameModel
public NameViewModel()
{
this.Model = new NameModel();
}
// Constructor has a specific model dictated to it
public NameViewModel(NameModel model)
{
this.Model = model;
}
//Model wrapper properties
public String Name
{
get { return Model.Name; }
set { Model.Name = value; }
}
}
和...
public class MainWindowViewModel
{
Private ObservableCollection<ViewModel> _NameViewModels;
Public Void MainWindowViewModel()
{
//Lets pretend we have a service that returns a list of models
var nameModels = Service.Request();
foreach(Model model in nameModels)
{
ViewModel viewmodel = new NameViewModel(model);
NameViewModel.Add(viewmodel);
}
}
Public ObservableCollection<ViewModel> NameViewModels
{
get
{
return _NameViewModels;
}
}
}
以这种方式,您的MainWindowViewModeldoes不能保留模型的完全独立的副本;它仅跟踪nameViewModels。每个名称ViewModel负责其自己的基础模型,同时仍然可以使该选项在施工期间使用A 特定模型传递给它。
所有与创建相关的问题都可以通过引入工厂设计模式来解决。工厂将照顾创建查看模型基于提供的模型。
public class MainWindowViewModel
{
private List<Model> _NamesModel;
private ObservableCollection<ViewModel> _NamesViewModel;
private IViewModelFactory factory;
public void MainWindowViewModel(IViewModelFactory factory)
{
//Lets pretend we have a service that returns a list of models
_NamesModel = Service.Request();
_NamesViewModel = factory.CreateNamesViewModels(_NamesModel);
}
public ObservableCollection<ViewModel> NamesViewModel
{
get
{
return _NamesViewModel;
}
}
}
更重要的是,您甚至可以摆脱视图模型中的Service
依赖关系并将其移至工厂本身,从而减少了将模型保持在视图模型中的需求(尽管如此,否则,删除模型可能在更复杂的方案中无法使用):
public ObservableCollection<ViewModel> CreateNamesViewModels()
{
var models = Service.Request();
return new ObservableCollection(models.Select(m => new ViewModel(m)));
}
另外,您的主窗口视图模型可以揭示使用工厂创建任何新实例的commands
。这样,没有模型泄漏以查看,也不会暴露创建细节(因为命令将隐藏实际实现)。