winforms icon indicating copy to clipboard operation
winforms copied to clipboard

DataGridView: sporadic NullReferenceException when trying to display the tooltip

Open koszeggy opened this issue 3 years ago • 5 comments

.NET version

.NET version: 6.0.300 Windows version: Windows 7 using classic theme

Did it work in .NET Framework?

I'm not 100% sure whether it works in .NET Framework but I did not face this issue earlier.

Issue description

System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Windows.Forms.Control.GetSafeHandle(IWin32Window window)
   at Interop.ComCtl32.ToolInfoWrapper`1..ctor(T handle, TTF flags, String text)
   at System.Windows.Forms.ToolTip.TryGetBubbleSize(IKeyboardToolTip tool, Rectangle toolRectangle, Size& bubbleSize)
   at System.Windows.Forms.ToolTip.ShowKeyboardToolTip(String text, IKeyboardToolTip tool, Int32 duration)
   at System.Windows.Forms.KeyboardToolTipStateMachine.ShowToolTip(IKeyboardToolTip tool, ToolTip toolTip)
   at System.Windows.Forms.KeyboardToolTipStateMachine.Transition(IKeyboardToolTip tool, ToolTip tooltip, SmEvent event)
   at System.Windows.Forms.KeyboardToolTipStateMachine.Transit(SmEvent event, IKeyboardToolTip source)
   at System.Windows.Forms.KeyboardToolTipStateMachine.<SetupInitShowTimer>b__25_0(Timer sender)
   at System.Windows.Forms.KeyboardToolTipStateMachine.<>c__DisplayClass27_0.<GetOneRunTickHandler>g__wrapper|0(Object sender, EventArgs eventArgs)
   at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam)

Steps to reproduce

It occurs randomly (up to a couple of times per day) at one of my customer's computer who uses Windows 7 with visual styles disabled (classic theme).

The DataGridView is rapidly updated via its DataSource (in every 100ms). It does not have any tooltip configured so it must be the default tooltip when the cell is too small to be able to display the entire text.

I apologize for not being able to provide a more specific reproduction but please refer to the provided strack trace, which clearly indicates that some handle must be invalid in the ToolInfoWrapper<T> constructor when the size of the tooltip is attempted to be determined.

I could never reproduce it locally maybe because I use Windows 10.

koszeggy avatar Jun 07 '22 08:06 koszeggy

Windows 7 using classic theme

W7 or W7SP1?

RussKie avatar Jun 07 '22 08:06 RussKie

OS Name: Microsoft Windows 7 Professional OS Version: 6.1.7601 Service Pack 1 Build 7601

koszeggy avatar Jun 07 '22 10:06 koszeggy

The DataGridView is rapidly updated via its DataSource (in every 100ms). It does not have any tooltip configured so it must be the default tooltip when the cell is too small to be able to display the entire text.

It's likely there's a race condition - e.g., a mouse is hovering a cell, which is rapidly updated with content, and the content may trigger the default cell tooltip. And while the tooltip is getting ready to show, the cell is updated recycling the handle.

As a workaround, can you try disabling DataGridView.ShowCellToolTips and see if it mitigates the issue?

RussKie avatar Jun 08 '22 01:06 RussKie

As a workaround, can you try disabling DataGridView.ShowCellToolTips and see if it mitigates the issue?

Actually this is what I'm doing now.

koszeggy avatar Jun 08 '22 14:06 koszeggy

I also encounter a NullReferenceException in a DataGridView with the exact same stack trace.

In my case, DataGridView.ShowCellToolTips is set to false.

In my case, the bug has nothing to do with updating the DataGridView. The exception is triggered regularly, when I use the Down or Up key to scroll through the DataGridView after releasing the key.

I encounter the bug only on Forms with a certain complexity (lots of databindings). I was not able to reproduce it on a simple Form with a simple DataGridView.

The bug appeared after upgrading from .NET Framework 4.7.2 to .NET 6.

Since the bug causes a database application that uses DataGridView to crash regularly without a reliable workaround, I would classify the bug as very serious.

dkoehler69 avatar Aug 19 '22 22:08 dkoehler69

@Olina-Zhang can your team try to reproduce this in .NET 8 with using keyboard navigation in a full DGV? The specific thing I'm interested in is the keyboard scrolling through the DataGridView.

merriemcgaw avatar Feb 28 '23 19:02 merriemcgaw

@merriemcgaw verified this issue on .NET 8.0 Preview3 latest build and .NET 6.0 both on win11 and win 7 OSes, we don't encounter the NullReferenceException when keyboard scrolling through the DataGridView(DataGridView.ShowCellToolTips is True). Following are our repro steps and attached a sample app, @koszeggy If this is something wrong, please correct me, thanks. NotRepro TestApp.zip

Amy-Li03 avatar Mar 01 '23 03:03 Amy-Li03

@Amy-Li03 and @merriemcgaw: As reported on 2022-08-20 (see above), I can confirm that the bug appears irregularly in .NET 6 under Win10 while DataGridView.ShowCellToolTips is set to false, and that I could not reproduce it in a simple example. I therefore suspect that some DataGridView background process either runs out of ressources (so it triggers the bug only under heavier load) or releases an object too early (so it triggers only after GC kicked in) or some asynchronic processes result in a race codition when setting a shared object to null.

dkoehler69 avatar Mar 01 '23 15:03 dkoehler69

@Amy-Li03 Can you try this again with ToolTips set to false and then also try it on Win10 (with ToolTips set both ways) because that is where it is being experienced. @dkoehler69 do you happen to have a sample app of what is happening for you? It could be something in the specific configuration of your DataGridView or your application data source. If we're unable to repro on our end it's very hard to determine what is happening to fix it unfortunately.

merriemcgaw avatar Mar 01 '23 20:03 merriemcgaw

There is one dialog in a very large application where I can consistently reproduce the issue. However, the dialog is complex (two levels of master-detail DataGridViews and a lot of databound controls), the code behind is 1,500 lines long and has a lot of references to other classes cascading from the front-end to the back-end. Sofar, when I try to remove parts of it in order to narrow down the issue, the issue itself stops to reproduce.

I attempted to narrow down the issue by out-commenting subroutines and lines of code. This way I discovered that the issue stopped appearing when I removed the instruction to update a BindingSource.Filter bound to a DataSet of a DataGridView used for the details of a master-detail relation. The instruction to change the filter is very simple:

private void UpdateDetailFilter(int? masterId)
{
  detailBindingSource.Filter = masterId is null
    ? "master_id IS NULL"
    : $"master_id = {masterId.Value}";
}

When out-commenting this instruction the issue disappears when debugging. When I set a break-point on the instruction, the issue also disappears. It does not reappear, when I set a breakpoint, stop at the breakpoint, then remove the breakpoint and continue.

The issue only appears when using the UP or DOWN key for navigation in the master DataGridView (which then calls the UpdateFilter method via its own BindingSource's CurrentChanged event handler), but not, when I select a row in the master DataGridView with the mouse, although the execution path for updating the filter is the same in both cases.

dkoehler69 avatar Mar 02 '23 00:03 dkoehler69

@merriemcgaw re-tested this on .NET 8.0 Preview3 latest build and .NET 6.0 both on win10, win11 and win 7 OSes (with ToolTips set True & False), we still cannot repro it. @dkoehler69 thanks for your detailed info, in order to investigate this further, could you please provide a sample app for us?

Amy-Li03 avatar Mar 02 '23 02:03 Amy-Li03

Thank you for the fix. Since opening this post it occurred also on my Windows 11 machine but only a few times, mainly during debugging after trying to continue the execution. In the end I built in a workaround by subscribing the Application.ThreadException and AppDomain.CurrentDomain.UnhandledException events.

So I'm not sure if I could prove it reliably whether the fix really works. @dkoehler69's repro seems promising though.

koszeggy avatar Mar 02 '23 09:03 koszeggy

@koszeggy I'm glad you were able to find a solution. @Amy-Li03 thanks for all the repro tries 😄 . I am going to close the issue as there is no action to take at this point on our side.

merriemcgaw avatar Mar 09 '23 22:03 merriemcgaw