AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
26.1k stars 2.26k forks source link

System.NullReferenceException in Avalonia.Controls.Utils.KeyboardHelper #16199

Open scottdoingwork opened 4 months ago

scottdoingwork commented 4 months ago

Describe the bug

var keymap = TopLevel.GetTopLevel(target)!.PlatformSettings!.HotkeyConfiguration; TopLevel.GetTopLevel(target) returns null, causing program crash.

System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=Avalonia.Controls.DataGrid StackTrace: at Avalonia.Controls.Utils.KeyboardHelper.GetPlatformCtrlOrCmdKeyModifier(Control target) in Avalonia.Controls.Utils\KeyboardHelper.cs:line 22 ...... at Avalonia.Win32.WindowImpl in src\Windows\Avalonia.Win32\WindowImpl.AppWndProc.cs 769

To Reproduce

Put DataGrid in a popup. Pressing mouse left button on datagrid let popup close immediately.

Expected behavior

Program won't crash in this situation.

Avalonia version

11.0.11

OS

Windows

Additional context

No response

MidnightEmpire commented 4 months ago

Same issue... Maybe exist some workaround?

timunie commented 4 months ago

Best "workaround" would be to clone the source, try to solve the issue and file a PR.

maxkatz6 commented 4 months ago

Yeah, it should be easy to add a null check. Not necessary the best solution there, as PlatformSettings should not be null for popups.

KittySey commented 4 months ago

I encountered a similar issue. The problem is a race condition when the DataGrid is removed from the Visual Tree before input handling is completed.

To avoid this in your case, close the popup asynchronously on the UI thread. Otherwise, the DataGrid will be detached from the Visual Tree and its VisualRoot set to null before the method in KeyboardHelper can retrieve the VisualRoot element. Here's a simple example:

private void DataGrid_OnCellPointerPressed(object? sender, DataGridCellPointerPressedEventArgs e)
{
    Dispatcher.UIThread.Post(() => myPopup.IsOpen = false);
}

For more info about the UI thread, see: https://docs.avaloniaui.net/docs/guides/development-guides/accessing-the-ui-thread