Search code examples
wpfsilverlightmvvmitemscontrol

How to make ItemsControl choose different templates depending on run-time type


I have a xaml page that has an ItemsControl control on it. ItemsControl is bound to Guests which is ObservableCollection. Guests collection can have objects of two different types: USGuest and UKGuest, both inheriting from Guest. Is it possible to make two (or more) templates for ItemsControl and make it automatically choose between them depending on the run-time type of the current item in collection?


Solution

  • Sorry, I didn't mean to be a party pooper and not offer a solution. But this is one of the biggest hurdles I run into when using MVVM in Silverlight.

    One thing I've done in the past is use a UserControl with just a ContentPresenter inside as the ItemsTemplate. (So many layers!) In the UserControl, when the DataContext changes, I would chose a template to use from the resources of the UserControl. (The templates would not actually have to be inside the UserControl, but I like that encapsulation the best.)

    MainPage:

    <UserControl>
    
      <UserControl.Resources>
        <DataTemplate x:key="itemTemplate">
          <my:ItemView />
        </DataTemplate>
      </UserControl.Resources>
    
      <ItemsControl ItemTemplate="{StaticResource itemTemplate}" />
    </UserControl>
    

    ItemView.xaml:

    <UserControl>
      <UserControl.Resources>
        <DataTemplate x:Key="Template1">
          <!-- Template #1 -->
        </DataTemplate>
        <DataTemplate x:Key="Template2">
          <!-- Template #2 -->
        </DataTemplate>
      </UserControl.Resources>
    
      <ContentPresenter Name="presenter"
                        Content="{Binding}" />
    
    </UserControl>
    

    ItemView.xaml.cs

    ...
    OnDataContextChanged(...)
    {
      var content = this.DataContext as MyDataType;
      DataTemplate template;
      switch (content.State) 
      {
        case State1:
          template = this.Resources["template1"] as DataTemplate;
          break;
        case State2:
          template = this.Resources["template2"] as DataTemplate;
          break;
      }
      this.presenter.ContentTemplate = template;
    }
    ...
    

    And if you're still following along, note that Silverlight also doesn't provide an OnDataContextChanged method like you get in WPF. So, to cover that, see what Jeremy Likness says about it over here:

    http://www.codeproject.com/Articles/38559/Silverlight-DataContext-Changed-Event.aspx

    I use that pretty often. Thanks, Jeremy!

    Also, there are some pretty severe limitations to this as well, when compared to all of the power that WPF gives you in that arena. For instance, there really is no good way do fake a ItemContainerStyle Selector. (That I know of.)