View only properties (eg: IsSelected) and the Model in MVVM
Asked Answered
C

1

6

Consider a WPF app that is being written using MVVM. The app needs to display a list of Employees (FirstName, LastName, Title) and you can select multiple to delete.

The model in this case would be "Employee" and it would implement INotifyPropertyChanged.

The View would be the "EmployeeListView" which would implement the XAML to display a collection of Employees.

The ViewModel would be "EmployeeListViewModel" which would expose an ObservableCollection, that can be bound to the EmployeeListView.

My question is: Where should the "IsSelected" property live?

  1. In the Model? (I dont like this idea, as the model now is exposing a property that is only required by a view and has nothing to do with the actual domain object, also, this property would be useless, if I implemented the view differently and didnt allow deletion of multiple employees at once).
  2. In the "EmployeeListViewModel" as a separate Dictionary collection, that would track whether an employee is selected or not? (Or even just a HashSet containing all selected employees). I dont like this much as the binding in the view is no longer straight forward.
  3. Implement a separate EmployeeViewModel, that wraps the Employee object and exposes the IsSelected property. The EmployeeListViewModel then will expose its collection as a ObservableCollection. I like this solution the best, but I always thought that there is one ViewModel per View and in this case, I have 2 view-models for my view. Is that a deviation from the MVVM pattern or is this the typical way to implement MVVM? (references?)
Consistency answered 12/8, 2013 at 2:51 Comment(0)
B
8

Create a reusable Generic SelectableItem that wraps each item in the EmployeeList:

Simple example:

public class SelectableItem<T>: INotifyPropertyChanged
{
    public bool IsSelected {get;set;} //PropertyChanged(), etc

    public T Value {get;set;}
}

then in the ViewModel:

public ObservableCollection<SelectableItem<Employee>> Employees {get;set;}

and in the View:

<DataTemplate>
   <CheckBox IsChecked="{Binding IsSelected}" Content="{Value.FullName}"/>
</DataTemplate>

Then you can retrieve all selected employees just by:

var selectedemployees = Employees.Where(x => x.IsSelected).Select(x => x.Value);
Bison answered 12/8, 2013 at 3:11 Comment(4)
I do like this solution. But although I do ask about implementing IsSelected, my question is also about whether its kosher is MVVM to have multiple ViewModels being used by one View. Also, isnt SelectableItem a ViewModel and in which case this is similar to my solution #3, but just implemented in a more generic way? (What if I had more UI specific items to track - IsChecked, IsSelected, etc, and not all UIs would need these different properties to be tracked)Consistency
It is totally acceptable to have multiple VM in on View. In fact, you can think that every control on a View is a View itself. The best example is when you have a DataGrid where every row will have his own VM.Querist
If there's one thing I could go back and tell myself 5 years ago it's NEVER BE AFRAID TO MAKE SOMETHING A VIEW MODEL!Canales
I prefer Item to Value since Value may be confused with a nullable typeCanales

© 2022 - 2024 — McMap. All rights reserved.