tags:

views:

33

answers:

2

Hello,

I'm trying to work out how I can alter the template depending on the size and number of items. This is very similar to the ribbon which dynamically changes depending on the size, or Windows 7 thumbnail of programs.

In this case, it's an ItemTemplate of a ListBox and I want to reduce the size of the image or not display it, rather than having scroll bars.

<ListBox ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Title}" />                        
                <Image Source="{Binding ImageUrl}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Thanks

+2  A: 

You probably want to use the DataTemplateSelector functionality in WPF:

From the link:

Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object. Note that if you have objects of different types you can set the DataType property on the DataTemplate. If you do that then there is no need to create a DataTemplateSelector. Furthermore, if you have objects of the same type but with different properties, you can also consider using a DataTrigger or a data converter. For more information, see Data Templating Overview.

Or alternatively, as mentioned above, a DataTrigger may be of use.

cristobalito
A DataTemplateSelector is meant to switch based on an individual item, it is, or should be, independent of other the items: If an item is added to the collection, will the templateselector be called for all of the existing items as well? Will all templates refresh? I'm not sure, but i don't think so.
Bubblewrap
Good point - a data trigger to a suitable property on the parent control might be the way forward then.
cristobalito
+2  A: 

You could set a style on the ListBox, which switches ItemTemplate based on the number of items.

<ListBox ItemsSource="{Binding Items}">
    <ListBox.Resources>
        <local:SizeConverter x:Key="SizeConverter"/>
        <DataTemplate x:Key="SmallTemplate"></DataTemplate>
        <DataTemplate x:Key="MediumTemplate"></DataTemplate>
        <DataTemplate x:Key="LargeTemplate"></DataTemplate>
    </ListBox.Resources>
    <ListBox.Style>
        <Style TargetType="ListBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Items.Count, Converter={StaticResource SizeConverter}}" Value="Small">
                    <Setter Property="ItemTemplate" Value="{StaticResource SmallTemplate}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Items.Count, Converter={StaticResource SizeConverter}}" Value="Medium">
                    <Setter Property="ItemTemplate" Value="{StaticResource MediumTemplate}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Items.Count, Converter={StaticResource SizeConverter}}" Value="Large">
                    <Setter Property="ItemTemplate" Value="{StaticResource LargeTemplate}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.Style>            
</ListBox>

The SizeConverter would be an IValueConverter which returns a size category based on the incoming count, the convert method could be something like this:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    int count = (int)value;
    if (count < 4) return "Large";
    if (count < 12) return "Medium";            
    return "Small";
}
Bubblewrap
Thanks - have bound the ListBox.ItemTemplate to an IMultiValueConverter which takes the available size and number of items and returns the appropriate resource.
escouser