dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.42k stars 985 forks source link

Cell using 'DisplayMember' to find and set value resulting in setting bad value. #11311

Open bukowa opened 6 months ago

bukowa commented 6 months ago

.NET version

$ dotnet --info
.NET SDK:
 Version:           8.0.101   
 Commit:            6eceda187b
 Workload version:  8.0.100-manifests.30fce108

Did it work in .NET Framework?

Not tested/verified

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

I created very simple showcase here https://github.com/bukowa/Issue_WinForms_FormattedValue As you can see if the DisplayMember returns the same value it will always be set to the first one.

Basically the value will be set to the first matching occurence of the DisplayMember found in the BindingList. Animation

The code is here https://github.com/dotnet/winforms/blob/1e92b290a6611cdabab4add02b738e9456e5d885/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs#L1508 https://github.com/dotnet/winforms/blob/1e92b290a6611cdabab4add02b738e9456e5d885/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.cs#L1674

Steps to reproduce

https://github.com/bukowa/Issue_WinForms_FormattedValue

elachlan commented 6 months ago

Maybe its the ItemComparer? It looks like its comparing based on the DisplayText. https://github.com/dotnet/winforms/blob/c926856b3313d34df58e82c73675b4cf30b6e604/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.ItemComparer.cs#L8-L33

elachlan commented 6 months ago

@Olina-Zhang can your team please test this to confirm?

bukowa commented 6 months ago

Maybe its the ItemComparer? It looks like its comparing based on the DisplayText.

https://github.com/dotnet/winforms/blob/c926856b3313d34df58e82c73675b4cf30b6e604/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.ItemComparer.cs#L8-L33

I tried setting breakpoint at this method and it was never executed. Upgraded to

$ dotnet --info
.NET SDK:
 Version:           8.0.204
 Commit:            c338c7548c
 Workload version:  8.0.200-manifests.7d36c14f
MelonWang1 commented 6 months ago

@elachlan This issue also repro's in .NET9.0/8.0/7.0/6.0/5.0/3.1 and .NET framework app.

https://github.com/dotnet/winforms/assets/94418985/c3a31d06-b5a0-4f4e-bc3a-431f6af9a17c

alandryz83 commented 6 months ago

Sent from my iPhoneOn May 6, 2024, at 3:44 AM, Melon Wang1 @.***> wrote: This issue also repro's in .NET9.0/8.0/7.0/6.0/5.0/3.1 and .NET framework app. https://github.com/dotnet/winforms/assets/94418985/c3a31d06-b5a0-4f4e-bc3a-431f6af9a17c

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

LeafShi1 commented 6 months ago

The stack trace when switching Kitten name:

        System.Windows.Forms.dll!System.Windows.Forms.ComboBox.RefreshItems() Line 3142 C#
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.OnDisplayMemberChanged(System.EventArgs e) Line 2963 C#
    System.Windows.Forms.dll!System.Windows.Forms.ListControl.SetDataConnection(object newDataSource, System.Windows.Forms.BindingMemberInfo newDisplayMember, bool force) Line 741 C#
    System.Windows.Forms.dll!System.Windows.Forms.ListControl.DisplayMember.set(string value) Line 114  C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridViewComboBoxCell.InitializeEditingControl(int rowIndex, object initialFormattedValue, System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle) Line 1397 C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.InitializeEditingControlValue(ref System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle, System.Windows.Forms.DataGridViewCell dataGridViewCell) Line 10130   C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.RefreshEdit() Line 25940 C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.DataGridViewDataConnection.ProcessListChanged(System.ComponentModel.ListChangedEventArgs e) Line 651 C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.DataGridViewDataConnection.currencyManager_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) Line 350 C#
    System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.OnListChanged(System.ComponentModel.ListChangedEventArgs e) Line 911  C#
    System.Windows.Forms.dll!System.Windows.Forms.CurrencyManager.List_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) Line 812    C#
    System.ComponentModel.TypeConverter.dll!System.ComponentModel.BindingList<ScratchProject.Human>.Child_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) Line 441 C#
    ScratchProject.dll!ScratchProject.Human.OnPropertyChanged(string propertyName) Line 34  C#
    ScratchProject.dll!ScratchProject.Human.Kitten.set(ScratchProject.Kitten value) Line 21 C#

Click on KittenId column:

>   System.Windows.Forms.dll!System.Windows.Forms.DataGridViewComboBoxCell.GetFormattedValue(object value, int rowIndex, ref System.Windows.Forms.DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, System.Windows.Forms.DataGridViewDataErrorContexts context) Line 1088   C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridViewCell.GetEditedFormattedValue(object value, int rowIndex, ref System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle, System.Windows.Forms.DataGridViewDataErrorContexts context) Line 1547  C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridViewCell.PaintWork(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, System.Windows.Forms.DataGridViewElementStates cellState, System.Windows.Forms.DataGridViewCellStyle cellStyle, System.Windows.Forms.DataGridViewAdvancedBorderStyle advancedBorderStyle, System.Windows.Forms.DataGridViewPaintParts paintParts) Line 3681  C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridViewRow.PaintCells(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle rowBounds, int rowIndex, System.Windows.Forms.DataGridViewElementStates rowState, bool isFirstDisplayedRow, bool isLastVisibleRow, System.Windows.Forms.DataGridViewPaintParts paintParts) Line 1657   C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridViewRow.Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle rowBounds, int rowIndex, System.Windows.Forms.DataGridViewElementStates rowState, bool isFirstDisplayedRow, bool isLastVisibleRow) Line 1469    C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.PaintRows(System.Drawing.Graphics g, System.Drawing.Rectangle boundingRect, System.Drawing.Rectangle clipRect, bool singleHorizontalBorderAdded) Line 20086  C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.PaintGrid(System.Drawing.Graphics g, System.Drawing.Rectangle gridBounds, System.Drawing.Rectangle clipRect, bool singleVerticalBorderAdded, bool singleHorizontalBorderAdded) Line 19968    C#
    System.Windows.Forms.dll!System.Windows.Forms.DataGridView.OnPaint(System.Windows.Forms.PaintEventArgs e) Line 17092    C#
    System.Windows.Forms.dll!System.Windows.Forms.Control.PaintWithErrorHandling(System.Windows.Forms.PaintEventArgs e, short layer) Line 8621  C#
merriemcgaw commented 6 months ago

Assigning this to @KlausLoeffelmann to evaluate. That said, this may not meet the bar for .NET if it works the same way in .NET Framework. We'll let you know.