Overview
In WPF’s ComboBox, the configuration of DisplayMemberPath, ItemTemplate, SelectedItem, SelectedValue, and SelectedValuePath varies depending on the element type of the collection bound to ItemsSource.
This article organizes the representative binding patterns and explains how to select the appropriate properties for each case.
Prerequisites / Environment
- Framework / Language: .NET 8 / C# 12
- Target control: WPF ComboBox
- Architecture: MVVM (binding through DataContext)
- Prior knowledge: WPF binding basics,
INotifyPropertyChanged - Verification environment: .NET 10 / Windows 11
The tables in this article were measured in the environment above.
Each caption states how its table was measured.
The following points were confirmed in that environment:
- Whether
SelectedValuePathis set changes whatSelectedValueholds. - Whether
DisplayMemberPathis set changes the string that is displayed. - What happens with the settings in Notes that are often said to fail: setting both
DisplayMemberPathandItemTemplate, a type difference betweenSelectedValueand the property atSelectedValuePath, and settingSelectedValuebeforeItemsSource.
Problem
When the element type of the collection bound to ItemsSource changes, the method for retrieving the selected value also changes.
For example, binding a list of strings differs from binding a list of objects that each have an ID and a display name: the ViewModel property type and the required XAML properties are different in each case.
Without understanding this distinction, the selected value may not be reflected, or the initial selection may fail to appear.
Cause / Background
The ComboBox exposes three selection-related properties:
| Property | Returns | Primary use |
|---|---|---|
SelectedItem |
The element itself from ItemsSource |
Pass the whole object to the ViewModel |
SelectedValue |
The value of the property named by SelectedValuePath |
Retrieve only a specific field such as an ID |
SelectedIndex |
The zero-based index of the selected row | Manage position only |
When ItemsSource holds strings, SelectedItem returns a string.
When ItemsSource holds objects and SelectedValuePath is set, SelectedValue returns the value of the specified property.
The appropriate binding target depends on the data structure, so the configuration must be aligned accordingly.
What the three properties return for the same selection can be confirmed by selecting an item and reading them back.
| configuration | SelectedItem | SelectedValue | SelectedIndex | displayed |
|---|---|---|---|---|
| no DisplayMemberPath / no SelectedValuePath | Item(20, beta) | Item(20, beta) | 1 | type name (Item.ToString()) |
| DisplayMemberPath=Name | Item(20, beta) | Item(20, beta) | 1 | beta |
| + SelectedValuePath=Id | Item(20, beta) | 20 (Int32) | 1 | beta |
| SelectedValuePath=Name | Item(20, beta) | beta (String) | 1 | beta |
Measured on .NET 10 / Windows 11 by selecting the second of three items carrying an Id and a Name. displayed is the string shown on the closed ComboBox.
Without SelectedValuePath, SelectedValue returns the item itself. The table above describes it as the value at SelectedValuePath; when that path is unset, what comes back is the same object as SelectedItem.
Setting SelectedValuePath=Id produces the Int32 20, changing the type as well. Passing only an ID to the view model requires that setting.
DisplayMemberPath affects only what is displayed and leaves SelectedValue untouched. The two are independent.
Five Implementation Patterns
Five representative patterns, formed by the element type in ItemsSource combined with what the ViewModel needs to hold.
Even with the same element type, the configuration changes with how the selection is received and how the display is built.
Some change what is rendered; others render the same and differ only in what lands in SelectedValue (Patterns B and C).
DisplayMemberPath render a single string, whereas ItemTemplate is applied to the selected item as well, allowing several fields to be shown side by side.Pattern A: String List
When ItemsSource is ObservableCollection<string>, DisplayMemberPath is unnecessary.
Binding SelectedItem to a string property in the ViewModel is sufficient.
<ComboBox ItemsSource="{Binding Regions}"
SelectedItem="{Binding SelectedRegion}" />
The corresponding ViewModel implementation is as follows.
public ObservableCollection<string> Regions { get; } = new()
{
"Northeast", "Midwest", "South", "West"
};
private string? _selectedRegion;
public string? SelectedRegion
{
get => _selectedRegion;
set { _selectedRegion = value; OnPropertyChanged(); }
}
Binding SelectedItem to a type other than string (for example, int) results in a type mismatch and the binding will not reflect the selection.
Pattern B: Object List + DisplayMemberPath + SelectedItem
When ItemsSource is ObservableCollection<T> and the entire selected object is needed in the ViewModel, specify the display property with DisplayMemberPath and bind SelectedItem to a property of type T.
<ComboBox ItemsSource="{Binding Departments}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedDepartment}" />
The above XAML displays the Name property of each Department object while binding the entire selected Department to SelectedDepartment.
The model and ViewModel definitions are as follows.
public class Department
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
public ObservableCollection<Department> Departments { get; } = new()
{
new Department { Id = 1, Name = "Sales" },
new Department { Id = 2, Name = "Engineering" },
new Department { Id = 3, Name = "Administration" },
};
private Department? _selectedDepartment;
public Department? SelectedDepartment
{
get => _selectedDepartment;
set { _selectedDepartment = value; OnPropertyChanged(); }
}
After selection, any field such as SelectedDepartment.Id or SelectedDepartment.Name is accessible.
Holding the whole object in the ViewModel makes it straightforward to reference multiple fields later.
Pattern C: Object List + DisplayMemberPath + SelectedValuePath
This pattern applies when only a specific field — such as an ID — needs to be stored in the ViewModel.
Specify the desired property name in SelectedValuePath and bind SelectedValue to a property of the matching type.
<ComboBox ItemsSource="{Binding Departments}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValue="{Binding SelectedDepartmentId}" />
The corresponding ViewModel property that holds the selected Id is defined as follows.
private int _selectedDepartmentId;
public int SelectedDepartmentId
{
get => _selectedDepartmentId;
set { _selectedDepartmentId = value; OnPropertyChanged(); }
}
A type difference between SelectedValue and the property named by SelectedValuePath did not break the selection in the measurement: with an int Id and a source property of type string holding "20", the item with Id 20 was selected, and selecting another item wrote back the string "30" (see Notes). With a property declared as object holding "20", however, the Int32 value 30 was written back, changing the value’s type. Keeping the ViewModel property the same type as the path is still clearer.
SelectedItem and SelectedValue can coexist; updating one automatically updates the other.
Pattern D: Custom Display with ItemTemplate
When multiple fields need to appear in a single row, or when an icon is included alongside text, use ItemTemplate.
DisplayMemberPath and ItemTemplate cannot be set together: setting both threw InvalidOperationException from code, and XamlParseException from XAML.
For custom display, use ItemTemplate only and remove DisplayMemberPath.
<ComboBox ItemsSource="{Binding Employees}"
SelectedItem="{Binding SelectedEmployee}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" Width="40" Foreground="Gray"/>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The Employee model referenced by this XAML is defined as follows.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
When different layouts are needed for the collapsed selection display versus the expanded dropdown list, use ContentTemplate alongside ItemContainerStyle instead of relying on ItemTemplate alone.
Pattern E: Enum List
For a fixed set of choices defined by an enumeration, generating the collection in the ViewModel with Enum.GetValues is more maintainable than using ObjectDataProvider in XAML.
The ViewModel generates the enum values as follows.
public enum Priority { Low, Medium, High }
public IEnumerable<Priority> Priorities { get; }
= (Priority[])Enum.GetValues(typeof(Priority));
private Priority _selectedPriority = Priority.Medium;
public Priority SelectedPriority
{
get => _selectedPriority;
set { _selectedPriority = value; OnPropertyChanged(); }
}
The XAML binds ItemsSource and SelectedItem to these ViewModel properties as follows.
<ComboBox ItemsSource="{Binding Priorities}"
SelectedItem="{Binding SelectedPriority}" />
SelectedItem is of type Priority.
An enum value has no property that holds its number, so SelectedValuePath cannot extract it: with SelectedValuePath="value__", SelectedValue was null. To get the number, cast the selected value, as in (int)SelectedPriority.
How to Choose
Which pattern applies is settled by the element type in ItemsSource and by what the ViewModel needs to hold.
- For simple values such as
stringor anenum, useSelectedItem, which hands back the element itself (Patterns A and E). - For objects where the whole selected object is needed, use
SelectedItem(Pattern B). - For objects where the ViewModel should hold only one value such as an ID, use
SelectedValuewithSelectedValuePath(Pattern C). - To separate the display name from the value stored in the ViewModel, combine
DisplayMemberPathwithSelectedValuePath. - To show several fields on one line, use
ItemTemplate(Pattern D). - Reserve
SelectedIndexfor cases where the position in the list itself carries meaning; otherwise prefer working with values or objects directly.
Keeping the ViewModel property type aligned with the ComboBox configuration is what prevents missed initial selections and update failures.
Comparing the Patterns
| Pattern | ItemsSource type |
Retrieving the selection | Best suited for |
|---|---|---|---|
| A: string list | ObservableCollection<string> |
SelectedItem (string) |
Options that are plain labels |
| B: objects + SelectedItem | ObservableCollection<T> |
SelectedItem (T) |
Referencing several fields after selection |
| C: objects + SelectedValuePath | ObservableCollection<T> |
SelectedValue (the property’s type) |
Only one field, such as an ID, is needed |
| D: ItemTemplate | ObservableCollection<T> |
SelectedItem (T) |
Showing several fields on one line |
| E: enum | IEnumerable<TEnum> |
SelectedItem (TEnum) |
Choosing from a fixed set of enum values |
Notes
| case | measured |
|---|---|
| DisplayMemberPath + ItemTemplate (code) | InvalidOperationException |
| DisplayMemberPath + ItemTemplate (XAML) | XamlParseException (inner InvalidOperationException) |
| SelectedValuePath=Id (int), source string property "20" | shown: SelectedIndex 1; after selecting index 2, source = 30 (String) |
| SelectedValuePath=Id (int), source object property holding "20" | shown: SelectedIndex 1; after selecting index 2, source = 30 (Int32) |
| enum items, SelectedValuePath=value__ | SelectedItem High, SelectedValue null |
| SelectedValue = 20 set before ItemsSource (code) | SelectedIndex 1 |
| SelectedValue bound to 30, ItemsSource assigned after display | SelectedIndex 2, source 30 |
Measured on .NET 10 / Windows 11 with three items whose Id values are 10, 20, and 30.
-
DisplayMemberPathandItemTemplatecannot be combined
Setting both throwsInvalidOperationException(from XAML, wrapped inXamlParseException). UseItemTemplatewhen custom display is needed and removeDisplayMemberPath. -
Setting the initial value for
SelectedValuecorrectly
When usingSelectedValuePath, if the ViewModel’s initial value does not exist inItemsSource, the selection state will be empty.
The order is not the cause: settingSelectedValuebeforeItemsSource, from code or through a binding withItemsSourceassigned after the window was shown, still selected the matching item once the items arrived. -
SelectedItemmatching considersEquals
SelectedItemdoes not strictly perform reference comparison; it involvesEquals-based matching.
With the default implementation, two separate instances with identical contents will not be considered equal, so setting a different instance as an initial value will not result in a visible selection.
To achieve value-based equality, overrideEqualsandGetHashCodeon the target type and implementIEquatable<T>if necessary.
When selection should be managed by an identifier or code value, useSelectedValuePathwithSelectedValue. -
Handling
null
To include a “no selection” option in the list, bind anullentry inItemsSource; theComboBoxdisplays it as a blank entry.
Use a nullable type (for example,string?orint?) for the ViewModel property.
Summary
The implementation pattern for a ComboBox follows from the type passed to ItemsSource.
Simple values call for SelectedItem; for objects, choose between SelectedItem and SelectedValue by whether the whole object is needed or one field suffices.
Most cases where an initial value fails to appear come down to a value in SelectedItem that matches no item in ItemsSource through Equals, or to an initial value that is not in ItemsSource at all.
The first is avoided by comparing a value such as an ID through SelectedValuePath, or by passing the same instance that ItemsSource holds. The second is not: with no matching item, SelectedValuePath selects nothing either, so pick the initial value from what ItemsSource contains.
- Why a WPF RadioButton Bound to an Enum Shows No Initial Selection — The Role of GroupName
- ComboBox (WPF Standard Control Demo App): measures what
Text,SelectedValue, andSelectedItemshow for the same items