WPF ComboBox ItemsSource Binding Patterns and Selected Value Retrieval

The right mix of DisplayMemberPath, SelectedItem, SelectedValue and SelectedValuePath depends on the ItemsSource element type. Covers five binding patterns.

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

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:


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).

Three ComboBox controls. The string list and the DisplayMemberPath one show only Baker, while the one using ItemTemplate shows 102 and Baker in two columns.
All three have the second entry selected. The string list and 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.

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.


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.