views:

902

answers:

3

I can't seem to set a ContentTemplate for a ComboBoxItem. There reason I'm trying to do this is I want to have 2 appearances for my data in the combo box. When the combo box is open (menu is down) I want a text box (with the name of the image) and an image control below it. When I select the item I want the combo box to just show a text box with the name of the image.

I thought I could achieve this by modifying the ItemTemplate and ItemContainerStyle of the ComboBox. The ItemContainerStyle contains the following ContentPresenter:

<ContentPresenter HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" x:Name="contentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>

So I assumed that I could just set the ContentTemplate here and it would work. But I can't seem to get it to work:

<DataTemplate x:Key="ComboBoxDataTemplate">
            <Grid>
                <TextBlock Text="{Binding Path='Name'}"/>
            </Grid>
        </DataTemplate>

<DataTemplate x:Key="ComboBoxItemTemplate">
            <StackPanel>
                <TextBlock Text="{Binding Path='Name'}"/>
                <Image Source="{Binding Path='Source'}" Width="64" Height="64"/>
            </StackPanel>
        </DataTemplate>

        <Style x:Key="ComboBoxItemStyle1" TargetType="ComboBoxItem">
...
            <Setter Property="ContentTemplate" Value="{StaticResource ComboBoxItemTemplate}"/>

...

Here's my combo box:

<ComboBox Width="70" Margin="3,0,0,0"
                        ItemsSource="{StaticResource Source}"
                        ItemTemplate="{StaticResource ComboBoxDataTemplate}"
                        ItemContainerStyle="{StaticResource ComboBoxItemStyle1}"
                        />

The only way I can get this to work is to remove the ContentPresenter from the ItemContainerStyle, and replace it with the contents of my custom template (ComboBoxItemTemplate). But I didn't think I should use this approach as it would mean the ContentPresenter no longer exists (and code in the ComboBox might rely on it existing).

Any help on showing a combo box with a different drop down and selected template would be greatly appreciated!

A: 

You can achieve this with just ItemsContainerStyle. Add your TextBlock and Image instead of the ContentPresenter. Add the VisualStateManager and toggle the Visibility of the Image control based on the Selected State of the VSM.

Jobi Joy
Whats the point of the ItemTemplate then, and also, won't not having a ContentPresenter cause a potential issue?
Mark Ingram
A: 

DataTemplate is mainly for your Data visualization, It is better to give all UI related dynamics inside the ControlTemplate(Control behaviors). There is no potential issue if you dont have a ContentPresenter. The only issue is that if you want to reuse this ControlTemplate from some other ComboBox. Then you can declare another clean Control template with a ContentPresenter there.

Jobi Joy
+1  A: 

The ComboBox.ItemTemplate is just a convenient way to set the ComboBoxItem.ContentTemplate. So your code above basically tries to set the ComboBoxItem.ContentTemplate twice.

As Jobi pointed out, you could try to use just a custom Style. You can safely exclude the ContentPresenter, if you always know the type of the Content. The ContentPresenter just allows you to use a DataTemplate to display some random data. But you could just replace it with a TextBlock and an Image. You just lose the ability to specify a DataTemplate.

The problem with Jobi's approach is that the select item won't show it's image, even if it's in the drop-down. Really the selected item is displayed in two locations (the drop-down and the main body of the ComboBox). In one location you want one DataTemplate, and in you want a different DataTemplate in the other.

Your best bet is to restyle the ComboBox. You can get the default Style from here. There is a ContentPresenter with the name "ContentPresenter". You would need to:

  1. Remove/change the name of the ContentPresenter, so the ComboBox will not automatically set the Content/ContentTemplate properties
  2. Bind the ContentPresenter.Content property like so: "{TemplateBinding SelectedObject}"
  3. Set the ContentPresenter.ContentTemplate property to your DataTemplate without the Image
  4. Set the ComboBox.ItemTemplate property to the DataTemplate with an Image and TextBlock like you were
  5. Give the ComboBox Style an explicit key, like x:Key="MyComboBoxStyle"
  6. Use the Style on your ComboBox, like Style="{StaticResource MyComboBoxStyle}"

This effectively ignores the ComboBoxItem.ContentTemplate when displaying the selected item in the body of the ComboBox, but uses it when display the ComboBoxItem in the drop-down.

Tom Goff