Closed AndrewDavidLees1974 closed 2 months ago
@AndrewDavidLees1974 can you include the call stack so we can make sure we're fully aligned here?
When the crash occurs it is after a sequence of rows have been deleted in the data grid view using the arrow keys to navigate to the next row after pressing Delete.
We found two different examples of crashes:
The first crash we found was:
at System.ThrowHelper.ThrowObjectDisposedException(Object instance)
at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.IHandle1..ctor(IHandle
1 handle)
at System.Windows.Forms.Control.GetSafeHandle(IWin32Window window)
at System.Windows.Forms.ToolTip.Hide(IWin32Window win)
at System.Windows.Forms.ToolTip.HideAllToolTips()
at System.Windows.Forms.ToolTip.BaseFormDeactivate(Object sender, EventArgs e)
at DevComponents.DotNetBar.RibbonForm.OnDeactivate(EventArgs e)
at System.Windows.Forms.Form.WmActivate(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at DevComponents.DotNetBar.RibbonForm.WndProc(Message& m)
at Emb.PricingSuite.RateAssessor.MainForm.WndProc(Message& m) in C:\Work\Radar2\EMB.PricingSuite.RateAssessor\src\implementation\MainForm.cs:line 5782
This appears to happen if the data grid is showing a tooltip for the last deleted row before you dispose the data grid view.
This is a different code path that appears to happen if the data grid row is still showing the tooltip from the penultimate row deleted before disposing the data grid view.
Exception of type System.ObjectDisposedException Cannot access a disposed object. Object name: 'Emb.Components.UI.Utilities.TriSortModelElementView'.
System.Private.CoreLib.dll!System.ThrowHelper.ThrowObjectDisposedException(object instance) Line 403
at //src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs(403)
System.Windows.Forms.dll!System.Windows.Forms.Control.CreateHandle() Line 4843
at //src/System.Windows.Forms/src/System/Windows/Forms/Control.cs(4843)
System.Windows.Forms.dll!System.Windows.Forms.Control.Handle.get() Line 2433
at //src/System.Windows.Forms/src/System/Windows/Forms/Control.cs(2433)
System.Windows.Forms.dll!System.Windows.Forms.Control.IHandle
(TriSortModelElementGrid is a sub class of DataGridView)
Hi, @AndrewDavidLees1974 could you please provide a sample application to repro this issue?
.NET version
.NET 8
Did it work in .NET Framework?
Yes
Did it work in any of the earlier releases of .NET Core or .NET 5+?
.NET 6 had other cell tooltip issues which resulted in us disabling cell tooltips. We found the behaviour had improved in .NET8 so we enabled them again.
.NET Framework did not have this issue, but .NET 8 has added these lines to OnCurrentCellChanged:
if (CurrentCell is not null && (ShowCellToolTips || (ShowCellErrors && !string.IsNullOrEmpty(CurrentCell?.ErrorText)))) { ActivateToolTip(false /activate/, string.Empty, CurrentCell.ColumnIndex, CurrentCell.RowIndex); KeyboardToolTipStateMachine.Instance.NotifyAboutGotFocus(CurrentCell); }
Which always shows a cell tooltip now when navigating the grid using arrow keys (not really sure why that is necessary though as cell tool tips before were only shown for truncated content?)
Issue description
When ShowCellToopTips is true for a DataGridView and the user navigates with arrow keys, the grid creates a KeyboardToolTip in the base Control PropertiesStore. This Tooltip is never disposed which leads to it remaining attached to the TopLevelForm. If the data grid is disposed while the cell tooltip is showing (e.g. removing a tab page that contains a data grid) and the top level form receives a WmActivate at the same time then the call to BaseFormDeactivate will crash in HideAllTooltips because it can't get the handle of the disposed grid.
The following in Tooltip Dispose code is also slightly odd:
Since RemoveAll called further up will set _topLevelControl to null and clear _tools so the call to TopLevelControl will always return null at this point. TopLevelControl is correct before the call to RemoveAll so perhaps its value should be cached or Tooltip detached from Deactivate earlier in the Dispose method?
Steps to reproduce
Dispose a data grid view that has an active keyboard cell tooltip in such a way as to force a WmActivate while the tooltip is still showing.
Disposing of the KeyboardToolTip in the data grid dispose method fixes this issue. I achieve this by calling the following code in my (sub classed) data grid before calling the base Dispose method:
private static readonly PropertyInfo KeyboardToolTipPropertyInfo = typeof(DataGridView).GetProperty("KeyboardToolTip", BindingFlags.Instance | BindingFlags.NonPublic);