Basically, I have the following scenario:
ViewModel: FooViewModel : BaseViewModel
, BarViewModel : BaseViewModel
Views: MainView
, FooView
, BarView
Right now I "inject" the view and set the DataContext
using DataTemplate
and DataTemplateSelector
. Obviously, my ItemsControl
ItemSource
is bound to an ObservableCollection<BaseViewModel>
in which it contains (for now) an instance of a FooViewModel
and a BarViewModel
The problem is I want to introduce a AlternateFooView
which I want to utilize the same FooViewModel
. I figure I'll create another DataTemplate
and have my DataTemplateSelector
return it, but there needs to be special logic to determine which DataTemplate to return (I can't just go by which ViewModel is there), and that means I'll have to have some type of property or field in the BaseViewModel. I don't know if that's really a good idea because that seems to be introducing a field/property into the ViewModel that is only used to select a view. It won't hurt my unit testing, but it seems like a waste to include a field just to help decide which UI View to choose. I don't think it breaks MVVM, but I'm curious if anyone out there has any other better ideas? The alternative ideas I had I dislike even more...
Idea #2:
- Turn FooViewModel into a base class that 2 different FooViewModel's extend (i.e. BaseFooViewModel, FooViewModel, DifferentFooViewModel). This seems stupid because there really isn't any difference between FooViewModel and DifferentFooViewModel aside from their class type.
Idea #3:
- Just copy FooViewModel and make it FooViewModel2 (it'll be exactly identical to FooViewModel). This seems even worse than idea #2.
public abstract class BaseViewModel : NotificationObject
{
//Common Stuff
}
public abstract MainViewModel : NotificationObject
{
public MainViewModel()
{
MyItems = new ObservableCollection<BaseViewModel>()
{
new FooViewModel();
new BarViewModel();
new FooViewModel(); //New Item -- I want it to use the DifferentFooView
}
//Load items from a DAL later
}
public ObservableCollection<BaseViewModel> MyItems { get; set; }
//Other Stuff
}
<l:MyItemsControl ItemSource={Binding MyItems} ContentTemplateSelector={StaticResource MyTemplateSelector} />
I agree with krishnaaditya that the question really boils down to what determines which View to use based on the state of the ViewModel. This type of logic is often placed into a template selector, which works great. If you don't want to put that logic into the template selector, consider externalizing it by using my Routed Template Selection approach. That makes it easy to delegate the template selection logic by using a routed event.
The idea you proposed in your comment about using a DataTrigger could also work, but that reintroduces the need for a property on the VM object that indicates which View to load (which you said you don't want). In my opinion, that's not necessarily a bad thing.