How do I structure MVVM with Collections?

后端 未结 4 474
不知归路
不知归路 2021-02-01 17:45

I\'m having trouble understanding how to apply the MVVM pattern when Lists/Collections are involved.

Say the MainModel has a few properties and methods, as

相关标签:
4条回答
  • 2021-02-01 17:59

    Here is an answer that I think addresses this issue very nicely using an ObservableViewModelCollection<TViewModel, TModel>

    It's nice and lazy. It takes an ObservableCollection and a ViewModelFactory in the ctor. I like it because it keeps state at the model layer where it belongs. User operations on the GUI can invoke commands at the VM which manipulate the M via public methods on the M. Any resulting changes at the M layer will be automatically handled by the class in this link.

    https://stackoverflow.com/q/2177659/456490

    Note my comment regarding SL vs. WPF

    0 讨论(0)
  • 2021-02-01 18:01

    Usually Models are nothing more than data objects. They shouldn't contain any code to do things like add/remove items from a list. This is the ViewModel's job.

    In your case, I would create a MainViewModel that has the following properties:

    • ObservableCollection<DetailViewModel> Details
    • ICommand AddDetailCommand
    • ICommand RemoveDetailCommand

    If your MainModel class is a data object, you can either expose it, or it's properties from the MainViewModel as well. Exposing it's Properties is the "MVVM purist" approach, while exposing the entire Model is sometimes more practical.

    Your MainViewModel is in charge of creating the initial list of DetailViewModels, and it is in charge of Adding/Removing these items as well. For example, in the PropertyChanged event for the MainViewModel.MainModel property, it might rebuild the MainViewModel.Details collection, and the CollectionChanged event for the MainViewModel.Details property would update MainViewModel.MainModel.Details

    0 讨论(0)
  • 2021-02-01 18:06

    You are right to have a separate DetailModels list and DetailViewModels list. The DetailViewModels list should be a property of type ObservableCollection<DetailViewModel>. You can populate the observable list when you set the Model (or at construction time, if you pass the model into the constructor of your ViewModel.)

    private ObservableCollection<DetailViewModel> m_details;
    public IEnumerable<DetailViewModel> Details
    {
       get { return m_details; }
    }
    

    You can the subscribe to m_details.CollectionChanged. This is where you can handle re-ordering the contents of the list in the Model.

    I hope this helps.

    0 讨论(0)
  • 2021-02-01 18:20

    In my experience, the only time you get away with exposing model objects to the view is if you're doing simple read-only presentation, e.g. displaying a string property in a ComboBox. If there's any kind of actual UI involving the object (especially one involving two-way data binding), a view model is needed.

    Typically, a master VM's constructor will look like this:

    public MasterViewModel(MasterModel m)
    {
       _Model = m;
       _Detail = new ObservableCollection<DetailViewModel>(m.Detail);
    }
    

    where MasterModel.Detail is a collection of DetailModel objects, and _Detail is a backing field for a Detail property that's exposed to the view.

    As far as adding, removing, and reordering items in this list is concerned, in the UI at least this will be done through commands on the MasterViewModel, which must manipulate both MasterModel.Detail and MasterViewModel.Detail. That's a bit of a pain, but unless you want to repopulate MasterViewModel.Detail after every change to MasterModel.Detail, it's really unavoidable.

    On the other hand, if you've been wondering "why would I ever need to write unit tests for view models?", now you know.

    0 讨论(0)
提交回复
热议问题