1

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.


Sample-Code (Adjusted obviously):
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} />


Thanks!
myermian
  • 31,823
  • 24
  • 123
  • 215
  • 1
    please correct me if i am missing anything. when do you want to use AlternateFooView and FooView? alternate items? – krishnaaditya Apr 14 '11 at 18:10
  • Well, originally I was thinking that the different View would depend on what's initially loaded into the ViewModel itself. I think your question actually helps quite a bit... maybe have a DataTrigger on the existing DataTemplate to choose the different View instead of 2 different DataTemplats? – myermian Apr 14 '11 at 18:17

1 Answers1

4

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.

Joe White
  • 94,807
  • 60
  • 220
  • 330
Josh Smith
  • 884
  • 6
  • 9
  • I feel honored that you answered my question (you have that reputation). While I'm not completely against the idea of having a property in the VM to indicate which DataTemplate to select, I wasn't sure if that breaks any MVVM best-practices or conventions. And, I also like that RoutedTemplateSelection class. Seems like a good thing to possibly use. – myermian Apr 14 '11 at 19:19
  • also, I was thinking of the DataTrigger as a way to avoid a special property on the VM since the View is determined by a the initial state of the ViewModel, so I can set it to one-time bind from an already existing property on the ViewModel. – myermian Apr 14 '11 at 19:21
  • 1
    @myermian, If the VM already has a property that can be used to determine which View to load, you're on easy street. It's really up to your preference whether to use a template selector or a data trigger. – Josh Smith Apr 14 '11 at 19:52