问题
I'm currently implementing a listbox in WPF that will have 2 alternative layouts for its items:
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.
回答1:
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.
来源:https://stackoverflow.com/questions/4934259/switching-listbox-itemtemplate-based-on-both-item-type-and-view-option