tags:

views:

114

answers:

1

I need to create several combo boxes to represent enumeration values. I want the values to be represented with some graphical preview to the left and text to the right. The "preview" part of the display might be a control, an image, or some other content. I've tried two approaches and failed both, so I'm curious what some alternatives could be. In my tests, the "preview" is a button because it's convenient to create, but in reality it will be either custom controls or DrawingImage controls.

For the first approach, I decided to use ContentPresenter to display the preview content for me. To do this, I created a control with the appropriate properties and template. I created a collection type that filled itself with instances of this control, then put an instance of the collection in my window's resources. I bound the ComboBox's ItemSource property to this collection. It works great when there's one ComboBox, but when there are multiple ComboBoxes using the resource, one of the ComboBoxes displays no values. I believe this is probably related to the fact that controls are its content, and some kind of reparenting issue is going on.

I decided this was the wrong way to approach it, and tried using the ItemTemplate of the ComboBox to do my dirty work. I redesigned the data class to inherit from DependencyObject instead of Control, and used the control's old style as the data template for the data type. This still has problems if multiple ComboBoxes bind to the same resource instance; the first ComboBox displays the preview content properly, but once you drop down the second ComboBox the preview content disappears from both ComboBoxes. In this approach, the selected item isn't displayed in the ComboBox, either, though I may have missed some other template I need to set for that. If I set the DataTemplate as the ComboBox's ItemTemplate directly, the selected item displays properly but ruins the control in the popup. I'm definitely not doing things right here.

The second method works if I create two instances of the collection in my resources, but that's not really practical. I could restructure my application to set up the bindings to private instances of the collection in code, but that seems kind of nasty. I could derive a new ComboBox for each type of collection and have it automatically use a new instance of the collection, but that seems like too much work. It seems like what I want would be something that isn't too uncommon, but I can't seem to find something that works. What am I doing wrong?

+2  A: 

You should not use FrameworkElement derived objects as contents in ItemControls since they can only be displayed once.

Instead, use DataTemplates to control how your items are displayed in your ComboBox. In really complex cases, you can use a DataTemplate selector. Bea Stollnitz has an excellent post about this here.

micahtan
I figured the first point was part of the problem, but even when I'm using DataTemplates I'm still running into the problem. Since both ComboBoxes use the same source collection, they're using the same control.
OwenP
Right, that's the problem. Image derives from FrameworkElement which means that it can't get re-used by different controls, it can only be displayed once. Instead, you'll want to have the Image control in your DataTemplate, and have your data expose an ImageSource instead of an image.
micahtan
That's what I agreed with in the last comment.The current workaround I'm using requires the data item to return an ImageSource where it used to return object. Now, when a data item wants to use a control as its preview, it is required to use a RenderTargetBitmap to render the control to an ImageSource, which is bound to the Image control in my DataTemplate.
OwenP
Have you looked into using VisualBrush instead?
micahtan