WPF DataGridComboBoxColumn loses value after focus is lost

Viewed 253

after trying a lot of (not working) solutions, I hope someone can help me.

If the focus of the selected row in my DataGrid is lost, the selected value of the ComboBox column will also be lost.

This is my XAML-Code

<Window x:Class="DataGridComboBoxTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:DataGridComboBoxTest"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <DataGrid Name="dataGrid"></DataGrid>
</Grid>

And her is the CS Code:

using System.Collections.Generic;
using System.Data;
using System.Windows;
using System.Windows.Controls;

namespace DataGridComboBoxTest
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            //Some Sample Data

            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("Name");
            dataTable.Columns.Add("Age");

            DataRow dataRow1 = dataTable.NewRow();
            dataRow1["Name"] = "John";
            dataRow1["Age"] = "33";
            dataTable.Rows.Add(dataRow1);

            DataRow dataRow2 = dataTable.NewRow();
            dataRow2["Name"] = "Emily";
            dataRow2["Age"] = "19";
            dataTable.Rows.Add(dataRow2);

            this.dataGrid.ItemsSource = dataTable.DefaultView;

            //Add ComboBox Column
            Dictionary<string, string> genders = new Dictionary<string, string>();
            genders.Add("f", "female");
            genders.Add("m", "male");

            DataGridComboBoxColumn dgCmbColumn = new DataGridComboBoxColumn();
            dgCmbColumn.Header = "Gender";

            dgCmbColumn.SelectedValuePath = "Key";
            dgCmbColumn.DisplayMemberPath = "Value";
            dgCmbColumn.ItemsSource = genders;


            this.dataGrid.Columns.Add(dgCmbColumn);
        }
    }
}

I tried a lot of solutions with Bindings, but nothing works for me.

2 Answers

If the focus of the selected row in my DataGrid is lost, the selected value of the ComboBox column will also be lost.

That's because you don't store the currently selected value somewhere.

Add a column to your DataTable:

dataTable.Columns.Add("Gender");

...and set the SelectedValueBinding property of the column:

dgCmbColumn.SelectedValueBinding = new Binding("Gender");

I suggest defining your columns in XAML as it is more readable than in code-behind:

<DataGrid Name="dataGrid" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
        <DataGridTextColumn Header="Age" Binding="{Binding Age}"/>
        <DataGridComboBoxColumn Header="Gender" SelectedItemBinding="{Binding Gender}" x:Name="myComboBoxColumn"/>
    </DataGrid.Columns>
</DataGrid>

In your code-behind, do not forget to also define a data column for the gender:

dataTable.Columns.Add("Gender");

For easy manipulation of gender, let's create an enum:

public enum Gender { Male, Female, Other }

And finally, set the ItemsSource of your column to your list of genders:

myComboBoxColumn.ItemsSource = new Gender[] { Gender.Male, Gender.Female, Gender.Other };

Total code-behind becomes:

InitializeComponent();

//Some Sample Data

DataTable dataTable = new DataTable();
dataTable.Columns.Add("Name");
dataTable.Columns.Add("Age");
dataTable.Columns.Add("Gender");

DataRow dataRow1 = dataTable.NewRow();
dataRow1["Name"] = "John";
dataRow1["Age"] = "33";
dataTable.Rows.Add(dataRow1);

DataRow dataRow2 = dataTable.NewRow();
dataRow2["Name"] = "Emily";
dataRow2["Age"] = "19";
dataTable.Rows.Add(dataRow2);

this.dataGrid.ItemsSource = dataTable.DefaultView;
myComboBoxColumn.ItemsSource = new Gender[] { Gender.Male, Gender.Female, Gender.Other };
Related