2

In our application we have a screen design feature which is comprised of a custom ScreenDesignPanel and a Property Grid with a ComboBox at the top which points to the selected item on the ScreenDesignPanel. This allows the user to select the UIElement via the ComboBox or via the mouse to set its properties. We achieve this by binding the ItemsSource of the ComboBox to the ScreenDesignPanel's Children collection, then binding their SelectedItems together. This works great.

However, for whatever reason, if the SelectedItem is a ContentControl or a subclass like Button the ItemTemplate specified for the ComboBox is ignored for the 'selected item area' but it is applied when displaying the item in the dropdown list. If the SelectedItem is not a ContentControl, the template is used in both cases.

This also is seemingly specific to the ComboBox. If we use any other selector control: ListBox, ListView, ItemsControl... even third-party ComboBox controls... they all work as expected, properly applying the DataTemplate. ComboBox is doing something internally which no other control is doing.

Note: Below is an over-simplified example for illustrative purposes of the issue only. It is not how we're actually using it as described above.

Also of note: In the DataTemplate for the ComboBox.ItemTemplate, we are only using properties (i.e. Foreground in the example), and are not displaying the DataContext (i.e. the actual ContentControl) itself. This is important because again, the actual control already exists on the ScreenDesignPanel and therefore can't be used for display in the ComboBox's ItemTemplate as it would have two parents which isn't allowed. In other words, it is being used purely as data here.

One last thing... we have a working solution in our app, which was to wrap the Children before binding it to the ComboBox.ItemsSource. However, I'm still curious as to why the ComboBox behaves the way it does which is SPECIFICALLY what I'm asking. (In other words, I'm not looking for other solutions to this design. We already have a working one. I'm looking for clarity on the odd behavior of the ComboBox itself.)

On to the code!

In the first example below, note how the data template is applied to everything in the dropdown, but the selected item area only uses a template if the selected item is not a ContentControl.

<ComboBox>

    <ComboBox.ItemTemplate>

        <DataTemplate>
            <TextBlock Text="I am the template" Foreground="{Binding Foreground}" />
        </DataTemplate>

    </ComboBox.ItemTemplate>

            <!-- Four 'Data' items for example only -->
    <TextBlock Text="I am a Red TextBox" Foreground="Red"/>

    <ListBox Foreground="Purple">
        <ListBoxItem>I am a Purple ListBox</ListBoxItem>
    </ListBox>

    <ContentControl Content="I am a Blue ContentControl" Foreground="Blue" />

    <Button Content="I am a Button with Green text" Foreground="Green" />

</ComboBox>

This second example shows that it is completely acceptable and fully supported to use a UIElement as the content of a ContentPresenter and still use a DataTemplate (via ContentTemplate) so you can use it in a purely-data role, allowing the template itself to define the visual appearance without displaying the UIElement itself, which is used purely as data here.

<ContentPresenter>

    <ContentPresenter.ContentTemplate>

        <DataTemplate>
            <TextBlock Text="I am the ContentTemplate" Foreground="{Binding Foreground}" />
        </DataTemplate>

    </ContentPresenter.ContentTemplate>

    <ContentPresenter.Content>
        <Button Content="I am the button" Foreground="Green" />
    </ContentPresenter.Content>

</ContentPresenter>

Again, the issue is specific to a ComboBox. I want to find out why the data template isn't applied in that single case, and how to force it to be applied, if possible.

Of note, ComboBox does define SelectionBoxItemTemplate which is separate from the regular ItemTemplate but the rub is that is read-only so you can't set it. We really don't want to re-template the ComboBox as that can mess up proper theming.

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • It's probably because `ContentControl.Content` is an object that gets wrapped in a `ContentPresenter` before use, and you can't use `StringFormat` an object. A `ContentPresenter` works because when rendered, it just displays the `Content` property with no wrapper control, so the value is a `string`. See the MSDN articles on [ContentPresenter.Content](http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter.content.aspx) and [ContentControl.Content](http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.content.aspx) for more details – Rachel Oct 31 '13 at 16:26
  • See my clarifications above. There is nothing special about the content property. It's just an object. Our code actually uses an attached property specifically created to feed the combo, but since the template isn't applied, the binding never hits and the attached property is never read. That's the issue... that the template never gets applied to the selected item if the selected item is a subclass of ContentControl. – Mark A. Donohoe Oct 31 '13 at 20:22
  • Hi @Rachel, I've updated this with more code examples showing this is specific to the ComboBox, not ContentPresenters. Any other ideas? – Mark A. Donohoe Nov 02 '13 at 17:32
  • This is an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Please describe what you are actually trying to achieve, as the current solution is not the intended use of the WPF constructs in question, so inconsistent behavior is to be expected. [UI is not data](http://stackoverflow.com/questions/14381402/wpf-programming-methodology/14382137#14382137). – nmclean Nov 02 '13 at 17:55
  • nmclean, I know MVVM. The UI in question is NOT a UI. It *is* data. It is a set of classes that just happen to be used ELSEWHERE as a UI, but not here. So no, this isn't an XY problem, nor is it applicable to the 'UI is not data' question that you linked to. – Mark A. Donohoe May 09 '15 at 05:40

1 Answers1

0

Have you tried explicitly setting the DataTemplate to the ContentControl.ContentTemplate property?:

<UserControl.Resources>
    <DataTemplate x:Key="DataTemplate">
        <TextBlock Text="{Binding Content, 
            StringFormat='Displayed via template: {0}'}" />
    </DataTemplate>
</UserControl.Resources>
...
<ContentControl Content="ContentControl" 
    ContentTemplate="{StaticResource DataTemplate}" />
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • You got this backwards. The ContentControl is an item within a ComboBox's Items collection. In other words, the ContentControl is being used as data, not as a UI item. – Mark A. Donohoe Oct 31 '13 at 17:42
  • just letting you know I added more to the question to better explain/demonstrate the issue. Any thoughts on why the ComboBox has that odd behavior? – Mark A. Donohoe Nov 02 '13 at 19:33
  • Sorry, but I can't shed any light on this situation... that's a curious problem you've discovered there. – Sheridan Nov 03 '13 at 03:35