From d4a338b5bb05fe62d1f2796b005f843ca2c7830b Mon Sep 17 00:00:00 2001 From: Abinesh p <120440951+abineshPalanisamy@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:32:03 +0530 Subject: [PATCH 1/4] Added fix for the Fix_Issue_11311 Added fix for the Fix_Issue_11311 --- .../DataGridView/DataGridViewComboBoxCell.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs index db5dc3b9c68..c1ac41c3229 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs @@ -1574,6 +1574,18 @@ private bool LookupValue(object? formattedValue, out object? value) return true; } + // When editing, use the actual selected item from the editing ComboBox. + // This avoids ambiguous lookup when DisplayMember values are duplicated. + if (OwnsEditingComboBox(RowIndex)) + { + object? selectedItem = EditingComboBox.SelectedItem; + if (selectedItem is not null) + { + value = GetItemValue(selectedItem); + return true; + } + } + Debug.Assert(DisplayMemberProperty is not null || ValueMemberProperty is not null || !string.IsNullOrEmpty(DisplayMember) || !string.IsNullOrEmpty(ValueMember)); From 562729fb5dcf8dcead67cf5d732603a41b315022 Mon Sep 17 00:00:00 2001 From: Abinesh p <120440951+abineshPalanisamy@users.noreply.github.com> Date: Mon, 8 Jun 2026 09:32:54 +0530 Subject: [PATCH 2/4] Updated the review changes Updated the review changes --- .../DataGridView/DataGridViewComboBoxCell.cs | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs index c1ac41c3229..50bf6deb173 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs @@ -1574,24 +1574,30 @@ private bool LookupValue(object? formattedValue, out object? value) return true; } - // When editing, use the actual selected item from the editing ComboBox. - // This avoids ambiguous lookup when DisplayMember values are duplicated. - if (OwnsEditingComboBox(RowIndex)) - { - object? selectedItem = EditingComboBox.SelectedItem; - if (selectedItem is not null) - { - value = GetItemValue(selectedItem); - return true; - } - } - Debug.Assert(DisplayMemberProperty is not null || ValueMemberProperty is not null || !string.IsNullOrEmpty(DisplayMember) || !string.IsNullOrEmpty(ValueMember)); object? item; if (DisplayMemberProperty is not null || ValueMemberProperty is not null) { + // When the cell is in edit mode, check the item the user actually selected first. + // A linear search through the data source would return the first item whose display + // property matches, which is wrong when multiple items share the same display text. + if (OwnsEditingComboBox(RowIndex)) + { + object? selectedItem = EditingComboBox.SelectedItem; + if (selectedItem is not null) + { + PropertyDescriptor displayProp = DisplayMemberProperty ?? ValueMemberProperty!; + object? selectedDisplayValue = displayProp.GetValue(selectedItem); + if (selectedDisplayValue is not null && selectedDisplayValue.Equals(formattedValue)) + { + value = GetItemValue(selectedItem); + return true; + } + } + } + // Now look up the item in the DataGridViewComboBoxCell datasource - this can be horribly inefficient // and it uses reflection which makes it expensive - ripe for optimization item = ItemFromComboBoxDataSource((DisplayMemberProperty ?? ValueMemberProperty)!, formattedValue); From 2a91b34e10ffa2e106d4f154e4d60c3df2e51bcf Mon Sep 17 00:00:00 2001 From: Abinesh p <120440951+abineshPalanisamy@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:21:09 +0530 Subject: [PATCH 3/4] Added unit test cases for the fix. Added unit test cases for the fix. --- .../Forms/DataGridViewComboBoxCellTests.cs | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs index 9518ee76988..67ed6a99b56 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Drawing; +using System.Runtime.CompilerServices; namespace System.Windows.Forms.Tests; @@ -15,6 +16,91 @@ public class DataGridViewComboBoxCellTests : IDisposable public DataGridViewComboBoxCellTests() => _dataGridViewComboBoxCell = new(); + private sealed class TestHuman : INotifyPropertyChanged + { + private TestKitten? _kitten; + + public TestKitten? Kitten + { + get => _kitten; + set + { + if (!ReferenceEquals(_kitten, value)) + { + _kitten = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(KittenId)); + } + } + } + + public string? KittenId => Kitten?.Id; + + public event PropertyChangedEventHandler? PropertyChanged; + + private void OnPropertyChanged([CallerMemberName] string? propertyName = null) + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + private sealed class TestKitten + { + public string? Name { get; set; } + + public string? Id { get; set; } + + public TestKitten Self => this; + + public string? DisplayName => Name; + } + + private static DataGridView CreateGrid( + BindingList humans, + BindingList kittens, + bool addDependentColumn = false) + { + DataGridView grid = new() + { + AutoGenerateColumns = false, + AllowUserToAddRows = false + }; + + DataGridViewComboBoxColumn comboColumn = new() + { + DataPropertyName = nameof(TestHuman.Kitten), + DisplayMember = nameof(TestKitten.DisplayName), + ValueMember = nameof(TestKitten.Self), + ValueType = typeof(TestKitten), + DataSource = kittens + }; + + grid.Columns.Add(comboColumn); + + if (addDependentColumn) + { + grid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = nameof(TestHuman.KittenId), + Name = "KittenId" + }); + } + + grid.DataSource = humans; + + return grid; + } + + private static Form CreateHostedForm(Control control) + { + Form form = new(); + form.Controls.Add(control); + control.Dock = DockStyle.Fill; + + form.Show(); + Application.DoEvents(); + + return form; + } + [Fact] public void AutoComplete_DefaultValue_IsTrue() => _dataGridViewComboBoxCell.AutoComplete.Should().BeTrue(); @@ -355,4 +441,105 @@ public void ParseFormattedValue_UsesParseFormattedValueInternal_WithValueType_Wh result.Should().Be("test"); } + + [WinFormsFact] + public void DataGridViewComboBoxCell_EndEdit_DuplicateDisplayMember_SelectSecond_CommitsSecondObject() + { + BindingList kittens = new(new[] + { + new TestKitten { Id = "1", Name = "Kitty1" }, + new TestKitten { Id = "2", Name = "Kitty1" }, + new TestKitten { Id = "3", Name = "Kitty1" } + }); + + BindingList humans = new() + { + new TestHuman { Kitten = kittens[0] } + }; + + using DataGridView grid = CreateGrid(humans, kittens); + using Form form = CreateHostedForm(grid); + + Assert.Equal(1, grid.Rows.Count); + + grid.CurrentCell = grid[0, 0]; + Assert.True(grid.BeginEdit(true)); + + ComboBox editingControl = Assert.IsType(grid.EditingControl); + editingControl.SelectedItem = kittens[1]; + + grid.NotifyCurrentCellDirty(true); + + Assert.True(grid.EndEdit()); + + Assert.Same(kittens[1], humans[0].Kitten); + Assert.Equal("2", humans[0].KittenId); + } + + [WinFormsFact] + public void DataGridViewComboBoxCell_EndEdit_DuplicateDisplayMember_SelectThird_CommitsThirdObject() + { + BindingList kittens = new(new[] + { + new TestKitten { Id = "1", Name = "Kitty1" }, + new TestKitten { Id = "2", Name = "Kitty1" }, + new TestKitten { Id = "3", Name = "Kitty1" } + }); + + BindingList humans = new() + { + new TestHuman { Kitten = kittens[0] } + }; + + using DataGridView grid = CreateGrid(humans, kittens); + using Form form = CreateHostedForm(grid); + + Assert.Equal(1, grid.Rows.Count); + + grid.CurrentCell = grid[0, 0]; + Assert.True(grid.BeginEdit(true)); + + ComboBox editingControl = Assert.IsType(grid.EditingControl); + editingControl.SelectedItem = kittens[2]; + + grid.NotifyCurrentCellDirty(true); + + Assert.True(grid.EndEdit()); + + Assert.Same(kittens[2], humans[0].Kitten); + Assert.Equal("3", humans[0].KittenId); + } + + [WinFormsFact] + public void DataGridViewComboBoxCell_EndEdit_DuplicateDisplayMember_UpdatesDependentProperty() + { + BindingList kittens = new(new[] + { + new TestKitten { Id = "1", Name = "Kitty1" }, + new TestKitten { Id = "2", Name = "Kitty1" } + }); + + BindingList humans = new() + { + new TestHuman { Kitten = kittens[0] } + }; + + using DataGridView grid = CreateGrid(humans, kittens, addDependentColumn: true); + using Form form = CreateHostedForm(grid); + + Assert.Equal(1, grid.Rows.Count); + + grid.CurrentCell = grid[0, 0]; + Assert.True(grid.BeginEdit(true)); + + ComboBox editingControl = Assert.IsType(grid.EditingControl); + editingControl.SelectedItem = kittens[1]; + + grid.NotifyCurrentCellDirty(true); + + Assert.True(grid.EndEdit()); + + Assert.Equal("2", humans[0].KittenId); + Assert.Equal("2", grid.Rows[0].Cells[1].Value); + } } From 6ed1a77269020fa3b49fd01fa3c60b16194a1588 Mon Sep 17 00:00:00 2001 From: Abinesh p <120440951+abineshPalanisamy@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:03:40 +0530 Subject: [PATCH 4/4] Revert "Added unit test cases for the fix." This reverts commit 2a91b34e10ffa2e106d4f154e4d60c3df2e51bcf. --- .../Forms/DataGridViewComboBoxCellTests.cs | 187 ------------------ 1 file changed, 187 deletions(-) diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs index 67ed6a99b56..9518ee76988 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewComboBoxCellTests.cs @@ -3,7 +3,6 @@ using System.ComponentModel; using System.Drawing; -using System.Runtime.CompilerServices; namespace System.Windows.Forms.Tests; @@ -16,91 +15,6 @@ public class DataGridViewComboBoxCellTests : IDisposable public DataGridViewComboBoxCellTests() => _dataGridViewComboBoxCell = new(); - private sealed class TestHuman : INotifyPropertyChanged - { - private TestKitten? _kitten; - - public TestKitten? Kitten - { - get => _kitten; - set - { - if (!ReferenceEquals(_kitten, value)) - { - _kitten = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(KittenId)); - } - } - } - - public string? KittenId => Kitten?.Id; - - public event PropertyChangedEventHandler? PropertyChanged; - - private void OnPropertyChanged([CallerMemberName] string? propertyName = null) - => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private sealed class TestKitten - { - public string? Name { get; set; } - - public string? Id { get; set; } - - public TestKitten Self => this; - - public string? DisplayName => Name; - } - - private static DataGridView CreateGrid( - BindingList humans, - BindingList kittens, - bool addDependentColumn = false) - { - DataGridView grid = new() - { - AutoGenerateColumns = false, - AllowUserToAddRows = false - }; - - DataGridViewComboBoxColumn comboColumn = new() - { - DataPropertyName = nameof(TestHuman.Kitten), - DisplayMember = nameof(TestKitten.DisplayName), - ValueMember = nameof(TestKitten.Self), - ValueType = typeof(TestKitten), - DataSource = kittens - }; - - grid.Columns.Add(comboColumn); - - if (addDependentColumn) - { - grid.Columns.Add(new DataGridViewTextBoxColumn - { - DataPropertyName = nameof(TestHuman.KittenId), - Name = "KittenId" - }); - } - - grid.DataSource = humans; - - return grid; - } - - private static Form CreateHostedForm(Control control) - { - Form form = new(); - form.Controls.Add(control); - control.Dock = DockStyle.Fill; - - form.Show(); - Application.DoEvents(); - - return form; - } - [Fact] public void AutoComplete_DefaultValue_IsTrue() => _dataGridViewComboBoxCell.AutoComplete.Should().BeTrue(); @@ -441,105 +355,4 @@ public void ParseFormattedValue_UsesParseFormattedValueInternal_WithValueType_Wh result.Should().Be("test"); } - - [WinFormsFact] - public void DataGridViewComboBoxCell_EndEdit_DuplicateDisplayMember_SelectSecond_CommitsSecondObject() - { - BindingList kittens = new(new[] - { - new TestKitten { Id = "1", Name = "Kitty1" }, - new TestKitten { Id = "2", Name = "Kitty1" }, - new TestKitten { Id = "3", Name = "Kitty1" } - }); - - BindingList humans = new() - { - new TestHuman { Kitten = kittens[0] } - }; - - using DataGridView grid = CreateGrid(humans, kittens); - using Form form = CreateHostedForm(grid); - - Assert.Equal(1, grid.Rows.Count); - - grid.CurrentCell = grid[0, 0]; - Assert.True(grid.BeginEdit(true)); - - ComboBox editingControl = Assert.IsType(grid.EditingControl); - editingControl.SelectedItem = kittens[1]; - - grid.NotifyCurrentCellDirty(true); - - Assert.True(grid.EndEdit()); - - Assert.Same(kittens[1], humans[0].Kitten); - Assert.Equal("2", humans[0].KittenId); - } - - [WinFormsFact] - public void DataGridViewComboBoxCell_EndEdit_DuplicateDisplayMember_SelectThird_CommitsThirdObject() - { - BindingList kittens = new(new[] - { - new TestKitten { Id = "1", Name = "Kitty1" }, - new TestKitten { Id = "2", Name = "Kitty1" }, - new TestKitten { Id = "3", Name = "Kitty1" } - }); - - BindingList humans = new() - { - new TestHuman { Kitten = kittens[0] } - }; - - using DataGridView grid = CreateGrid(humans, kittens); - using Form form = CreateHostedForm(grid); - - Assert.Equal(1, grid.Rows.Count); - - grid.CurrentCell = grid[0, 0]; - Assert.True(grid.BeginEdit(true)); - - ComboBox editingControl = Assert.IsType(grid.EditingControl); - editingControl.SelectedItem = kittens[2]; - - grid.NotifyCurrentCellDirty(true); - - Assert.True(grid.EndEdit()); - - Assert.Same(kittens[2], humans[0].Kitten); - Assert.Equal("3", humans[0].KittenId); - } - - [WinFormsFact] - public void DataGridViewComboBoxCell_EndEdit_DuplicateDisplayMember_UpdatesDependentProperty() - { - BindingList kittens = new(new[] - { - new TestKitten { Id = "1", Name = "Kitty1" }, - new TestKitten { Id = "2", Name = "Kitty1" } - }); - - BindingList humans = new() - { - new TestHuman { Kitten = kittens[0] } - }; - - using DataGridView grid = CreateGrid(humans, kittens, addDependentColumn: true); - using Form form = CreateHostedForm(grid); - - Assert.Equal(1, grid.Rows.Count); - - grid.CurrentCell = grid[0, 0]; - Assert.True(grid.BeginEdit(true)); - - ComboBox editingControl = Assert.IsType(grid.EditingControl); - editingControl.SelectedItem = kittens[1]; - - grid.NotifyCurrentCellDirty(true); - - Assert.True(grid.EndEdit()); - - Assert.Equal("2", humans[0].KittenId); - Assert.Equal("2", grid.Rows[0].Cells[1].Value); - } }