System.ArgumentException when selecting rows in WPF DataGrid
This article provides a resolution to resolve the
System.ArgumentException that occurs when you select rows in WPF DataGrid controls.
Original product version: Microsoft .NET Framework 4.5
Original KB number: 2909048
You've developed a Microsoft .NET Framework 4.x application that uses the Windows Presentation Foundation (WPF) DataGrid control. The DataGrid control's ItemsSource property is bound to a collection of custom objects. After modifying values for a row in the DataGrid control, and selecting a different row, you receive the following exception and callstack. This behavior only occurs when running the application on a computer with Microsoft .NET Framework 4.5 or later installed.
System.ArgumentException was unhandled
Message=An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary 2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary 2..ctor(IDictionary 2 dictionary, IEqualityComparer 1 comparer)
at System.Windows.Controls.Primitives.Selector.InternalSelectedItemsStorage..ctor(InternalSelectedItemsStorage collection, IEqualityComparer 1 equalityComparer)
at System.Windows.Controls.DataGrid.MakeFullRowSelection(ItemInfo info, Boolean allowsExtendSelect, Boolean allowsMinimalSelect)
The DataGrid's ItemsSource is bound to a collection of custom objects, whose type definition has overridden the Object.GetHashCode method. The overridden
GetHashCode method has an incorrect implementation that computes a hash based on mutable properties in the class. This is an application bug, which is exposed in Microsoft .NET Framework 4.5 and later. In Microsoft .NET Framework 4.5, the implementation for the WPF
Selector class was changed to make more extensive use of HashTables; in order to gain performance benefits.
Modify the custom object's type definition to abide by the guidelines of overriding
If a type computes its hash by relying on mutable properties, and the values of one or more of the mutable properties changes; then the computed hash returned from its overridden
GetHashCode method also changes. If this takes place while the object is stored in WPF's internal HashTable, then it's no longer retrievable based on the original hash. WPF detects that the object isn't available from the HashTable, and adds it again based on the new hash. It then attempts to insert related
Selector data into an internal Dictionary using a key. However, an exception occurs because an item with that key had already been added previously to the Dictionary.
You should override
GetHashCode only if:
- You can compute the hash code from fields that aren't mutable; or
- You can ensure that the hash code of a mutable object doesn't change while the object is contained in a collection that relies on its hash code.