4

我一直在使用 C# 开发 MVVM 应用程序,但在处理我的视图摘要的 ViewModels 集合时始终遇到一些问题。具体来说,它们都倾向于与 Model 作为 ViewModel 的私有成员的问题有关。

这方面的一个例子是创建新的 ViewModel(根据 View 的要求)。对于一些序言(尽管您可能不需要这些来帮助我)这里是示例模型和视图模型类:

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 处理模型(私有,视图看不到这些)和 ViewModel(公共用于视图消化)的集合:

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 compare(Model model)) 中创建一个公共方法,它将一个模型(准备删除等)与它的内部模型进行比较。如果模型被公开(破坏纯度),那么做一些事情会容易得多,比如找到连接到模型的 ViewModel。

4

2 回答 2

2

我可以同情其中一些问题。我最近编写了一个 MVVM 应用程序,其中经常出现类似的问题。诀窍之一是确定 - 明确 - 哪个类将负责 Model 实例。你想让它成为你的 MainWindowViewModel 吗?还是你的 NameViewModel?您不想在这两个类之间分担创建/删除模型的责任;你会有相当大的后勤噩梦。

其次,即使是“纯”的 MVVM 方法也没有规定您不能公开公开模型。你自己说过这样做可以省去很多麻烦:去做吧。MVVM 仅规定 ViewModel 不了解/访问 View。有许多“官方”MVVM 示例使用 INotifyPropertyChanged 接口来实现它们的模型,并直接绑定到模型上的属性。

就个人而言,我认为我会将 NameModel 的控制权交给 NameViewModel。这意味着您应该从 MainWindowViewModel 中完全删除 NameModel 列表。如果你想给 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;
        }
    }
}

这样,您的 MainWindowViewModel 不会保留完全独立的模型副本;它只跟踪 NameViewModels。每个 NameViewModel 负责自己的底层模型,同时仍然提供选项以在构建期间将特定模型传递给它。

于 2012-12-29T13:32:47.640 回答
1

所有与创建相关的问题都可以通过引入工厂设计模式来解决。工厂将负责根据提供的模型创建视图模型

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利用工厂创建任何新实例。这样,没有模型泄漏到查看,也没有暴露创建细节(因为命令将隐藏实际实现)。

于 2012-12-29T13:43:39.357 回答