Exception on DataGrid selection with a particular setup
- Dominant language
- C#
- Stars
- 7.7k
- Forks
- 1.3k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 61
Description
## Problem description
Under a particular set of circumstances, selecting a cell in a [`DataGrid`](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.datagrid) causes the application crash. The circumstances include
1. adding data to the backing `ObservableCollection<>` of the `DataGrid` by
2. triggering an `ICommand` bound to an element inside a [`MenuItem`](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.menuitem),
3. the `SelectedItem` was `null` before this trigger, and
4. the set by WPF to make (the binding of) `SelectedItem` not `null` is ignored.
## Steps to reproduce
My minimal reproduction is available at [TysonMN/ExceptionOnDataGridSelection](https://github.com/TysonMN/ExceptionOnDataGridSelection).
1. Run that reproduction
2. Click the `MenuItem`
3. Click the `Button`
4. Click the only cell in the only row and column of the `DataGrid`.
Here are some additional details in case they matter.
* .NET Core Version:
- Version: 5.0.201
- Commit: a09bd5c86c
* Windows version: 1909 (OS Build 18363.1440)
* Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes
## Expected behavior
I expect that cell to have focus. I do not expect the cell to appear selected. I do not expect an exception to be thrown. I do not expect the application to crash.
## Actual behavior
The application crashes because the exception
```
System.ArgumentNullException: 'Value cannot be null.
Parameter name: item'
```
is thrown with stack trace
```
PresentationFramework.dll!System.Windows.Automation.Peers.DataGridItemAutomationPeer.DataGridItemAutomationPeer(object item, System.Windows.Automation.Peers.DataGridAutomationPeer dataGridPeer) Unknown
PresentationFramework.dll!System.Windows.Automation.Peers.DataGridAutomationPeer.CreateItemAutomationPeer(object item) Unknown
PresentationFramework.dll!System.Windows.Automation.Peers.ItemsControlAutomationPeer.FindOrCreateItemAutomationPeer(object item) Unknown
PresentationFramework.dll!System.Windows.Automation.Peers.DataGridAutomationPeer.RaiseAutomationSelectionEvents(System.Windows.Controls.SelectionChangedEventArgs e) Unknown
PresentationFramework.dll!System.Windows.Controls.DataGrid.OnSelectionChanged(System.Windows.Controls.SelectionChangedEventArgs e) Unknown
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.SelectionChanger.End() Unknown
PresentationFramework.dll!System.Windows.Controls.DataGrid.MakeFullRowSelection(System.Windows.Controls.ItemsControl.ItemInfo info, bool allowsExtendSelect, bool allowsMinimalSelect) Unknown
PresentationFramework.dll!System.Windows.Controls.DataGrid.HandleSelectionForCellInput(System.Windows.Controls.DataGridCell cell, bool startDragging, bool allowsExtendSelect, bool allowsMinimalSelect) Unknown
PresentationFramework.dll!System.Windows.Controls.DataGridCell.OnAnyMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) Unknown
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) Unknown
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) Unknown
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) Unknown
PresentationCore.dll!System.Windows.UIElement.ReRaiseEventAs(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args, System.Windows.RoutedEvent newEvent) Unknown
PresentationCore.dll!System.Windows.UIElement.OnMouseDownThunk(object sender, System.Windows.Input.MouseButtonEventArgs e) Unknown
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) Unknown
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) Unknown
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) Unknown
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() Unknown
PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) Unknown
PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) Unknown
PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawMouseActions actions, int x, int y, int wheel) Unknown
PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.FilterMessage(System.IntPtr hwnd, MS.Internal.Interop.WindowMessage msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
PresentationCore.dll!System.Windows.Interop.HwndSource.InputFilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Unknown
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) Unknown
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) Unknown
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) Unknown
Project.exe!MyNamespace.App.Main() Unknown
```

## Workarounds
1. Remove the `MenuItem` but keep the `Button`. (This is the is the most surprising workaround to me.)
2. Initialize the backing `ObservableCollection<>` with an element. Clicking on that element does not reproduce the problem. However, clicking the `Button` and then clicking either element still reproduces the problem.
3. Initialize the backing `ObservableCollection<>` with the value `2` and change the getter of `MySelectedItem` to always return `2`.
4. Change `MySelectedItem` into an auto property.
## Additional comments
I created this minimal working example based on the reproduction provided in https://github.com/elmish/Elmish.WPF/issues/371.
I think it is reasonable to consider that the backing logic of the `SelectedItem` could ignore the value set by WPF.
In that initial issue, the set by WPF was not being completely ignored. Instead, it was being queued with the `Dispatcher` for later processing via `InvokeAsync`. WPF calls `TryGetMember` after calling `TrySetMember` (for the same member of course), so from the perspective of WPF at that moment, it appears as though its call to `TrySetMember` was ignored. I decided to go back to using `Invoke` when handling UI events (c.f. https://github.com/elmish/Elmish.WPF/pull/374), so the present issue is not blocking us over at Elmish.WPF.
Nonetheless, I think it would be reasonable to allow the user to toggle the ability select a row in a `DataGrid`. When the toggle is in the "selection-not-possible state", then the selection behavior would be the same as the reproduction that I have provided.
Contributor guide
Assessment
This issue has not been assessed yet.