Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

So far, I've done this using a DataTrigger to switch the ItemTemplate for the ListBox and it's working well:

<ListBox ItemsSource="{Binding Runs}" SelectedItem="{Binding SelectedRun}">
  <ListBox.Style>
    <Style TargetType="ListBox">
      <Setter Property="ItemTemplate" Value="{StaticResource tileTemplate}"/>
      <Style.Triggers>
        <DataTrigger Binding="{Binding ShowRunsAsIcons}" Value="True">
          <Setter Property="ItemTemplate" Value="{StaticResource iconTemplate}"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </ListBox.Style>
</ListBox>

However, the Runs collection to which the list is bound will also contain different types of object:

interface IRunItem
  // ...
class CompletedRunItem : IRunItem
  // ...
class PendingRunItem : IRunItem
  // ...

Each of the object types should have its own 'tile' and 'icon' templates (making 4 templates in total). What's the best way of switching on these two properties to according to the boolean ShowRunsAsIcons and the type of the list item?

I've considered using a pair of DataTemplateSelector subclasses -- one to choose between tile templates based on item type, and one to choose between icon templates based on item type -- but this just feels horribly clunky. I feel as though I should be taking advantage of WPF's ability to choose the correct template based on the object's type, but in this instance, I don't see how to combine that with the list's different view options.

Any ideas of how to do this that's more in the spirit of WPF?

Thanks.

Although I'm not convinced it's the best answer, I've changed my approach to take advantage of WPF's automatic template selection. I now have 'top-level' data templates defined for each of my concrete data classes.

These data templates contain nothing but a ContentControl whose ContentTemplate property is set via a DataTrigger, binding to the data context's ShowRunsAsIcons property.

As an example, here's the keyless data template for PendingRunItem:

<DataTemplate DataType="{x:Type Common:PendingRunItem}">
  <ContentControl Content="{Binding}">
    <ContentControl.Style>
      <Style TargetType="ContentControl">
        <Setter Property="ContentTemplate" Value="{StaticResource pendingTileTemplate}"/>
        <Style.Triggers>
          <DataTrigger Binding="{Binding DataContext.ShowRunsAsIcons, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource pendingIconTemplate}"/>
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </ContentControl.Style>
  </ContentControl>
</DataTemplate>

The icon and tile representations for the relevant classes are then just regular data templates. And the ListBox no longer needs its Style property defined:

<ListBox ItemsSource="{Binding Runs}" SelectedItem="{Binding SelectedRun}"/>

I'd be interested to know people's thoughts on this approach and its benefits and drawbacks when compared to using a DataTemplateSelector or two.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.