Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
My goal is to have a
ComboBox
where every drop down item has a specific text and a specific item associated with it so that, for example, if some clicks "blah" - the selected item will be 3.
As far as I can see - there's only one "Content" which represents both the Text and the Value. So how do I get both separately? (In either XAML or code, but
without Binding
.)
It is highly recommenced to use binding with XAML controls, however, you can define ComboBox items in XAML by the Items property:
<ComboBox x:Name="comboBox1"
SelectionChanged="ComboBox_SelectionChanged"
SelectedValuePath="Tag">
<ComboBox.Items>
<ComboBoxItem Tag="1">Item 1</ComboBoxItem>
<ComboBoxItem Tag="2">Item 2</ComboBoxItem>
<ComboBoxItem Tag="3">Item 3</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
and get selected items in code:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
Debug.WriteLine(comboBox1.SelectedValue);
Since the ComboBox item class has not a Value property, you can use the tag property to hold the corresponding value. Settings the SelectedValuePath property tells the ComboBox which property to use as Value.
The ComboBox
has an Items
property, which is simply just an ItemCollection
, which in turn is a specialized enumeration of object
s. So, in knowing this you can add any object
regardless of type to the collection of items.
In a typical scenario utilizing MVVM/DataBinding you would bind the ItemsSource
to auto-generate the Items
based upon any IEnumerable
object; most view-models would have the following as an example:
public class InventoryViewModel : INotifyPropertyChanged
public ObservableCollection<Car> Cars { get; private set; }
<ComboBox ItemsSource="{Binding Path=Cars, Mode=OneWay}" ... />
Notice that the collection has a bunch of Car
objects (not ComboBoxItem
s). Now, whether or not you populate a ComboBox
through DataBinding or directly, it will still create an ItemCollection
. So, if you forego the DataBinding route, how can you get a collection of Car
s? You could create each element directly within the ComboBox.Items
scope, or use DataBinding through a resource instead of a class (static or dynamic resource). If you don't do any DataBinding (even to a resource), you're code would look like this:
<ComboBox ... >
<ComoBox.Items>
<local:Car Brand="Ford" Model="Mustang" Id="1" />
<local:Car Brand="Ford" Model="Fusion" Id="2" />
<local:Car Brand="Cadillac" Model="CTS" Id="3" />
</ComboBox.Items>
</ComboBox>
With this in hand, the only other property you might need to set for the ComboBox
is the DisplayMemberPath
property. I say might because if you do not set this value, the ComboBox
will call ToString()
on the object to get the string version of the object, so it depends on whether or not the Car
class has a customized ToString()
. Now, when you listen to the SelectionChangedEvent
, the SelectedItem
will be a type of Car
instead of ComboBoxItem
. The SelectedValuePath
can also be set to a property of Car
and you can also get the SelectedValue
instead of the entire SelectedItem
, but just as before the actual underlying type would be a specific type instead of a ComboBoxItem
.
Additional Information:
The reason why ComboBoxItem
doesn't need a DisplayMemberPath
to be set is because the ToString()
member returns a formatted version of the Content
property:
public partial class FrameworkElement
internal virtual string GetPlainText()
return null;
public class Control : FrameworkElement
public override string ToString()
string plainText = null;
if (CheckAccess())
plainText = GetPlainText();
plainText = (string)Dispatcher.Invoke(DispatcherPriority.Send, new TimeSpan(0, 0, 0, 0, 20), new DispatcherOperationCallback(delegate(object o) {
return GetPlainText();
}), null);
if (!String.IsNullOrEmpty(plainText))
return SR.Get(SRID.ToStringFormatString_Control, base.ToString(), plainText);
return base.ToString();
public class ContentControl : Control
internal override string GetPlainText()
return ContentObjectToString(Content);
internal static string ContentObjectToString(object content)
if (content != null)
FrameworkElement feContent = content as FrameworkElement;
if (feContent != null)
return feContent.GetPlainText();
return content.ToString();
return String.Empty;
public class ListBoxItem : ContentControl { }
public class ComboBoxItem : ListBoxItem { }
Basically, any ContentControl
will use the Content
object in the ToString()
method at the end of the day. If you didn't want to create your own object, you can always use the KeyValuePair<TKey, TValue>
object as it can store a Key
and a Value
(the key would be the underlying value whereas the value would be the friendly text). Of course, Mehrzad Chehraz's answer of using the Tag
property is just as valid, since Tag
is meant to store any arbitrary value.
<ComboBox Height="154" HorizontalAlignment="Left"
ItemsSource="{Binding Path=Books}"
DisplayMemberPath="Title">
</ComboBox>
where Title is the member of Book
class Books
- collection of Book
objects
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.