浏览代码

Fix TrayIcon menu crash (#16024)

* Updated the TrayIcon in IntegrationTestApp to have an associated menu.
Updated App.axaml.cs to set the DataContext for binding and provide a command implementation.
Added a project reference to Avalonia.ReactiveUI.

* Updated CanExecuteChanged in NativeMenuItem.cs to thunk to the UI thread if it ends up running on a non-UI thread.

* Replace ReactiveUI with MiniMvvm to simplify integration tests app

---------

Co-authored-by: Max Katz <[email protected]>
Jonathan Gilbert 1 年之前
父节点
当前提交
79f29ccae7

+ 15 - 7
samples/IntegrationTestApp/App.axaml

@@ -1,13 +1,21 @@
 <Application xmlns="https://github.com/avaloniaui"
 <Application xmlns="https://github.com/avaloniaui"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             x:Class="IntegrationTestApp.App">
+             xmlns:self="using:IntegrationTestApp"
+             x:Class="IntegrationTestApp.App"
+             x:DataType="self:App"
+             RequestedThemeVariant="Default">
     <Application.Styles>
     <Application.Styles>
         <FluentTheme />
         <FluentTheme />
     </Application.Styles>
     </Application.Styles>
-  <TrayIcon.Icons>
-    <TrayIcons>
-      <TrayIcon Icon="/Assets/icon.ico">
-      </TrayIcon>
-    </TrayIcons>
-  </TrayIcon.Icons>
+    <TrayIcon.Icons>
+        <TrayIcons>
+            <TrayIcon Icon="/Assets/icon.ico">
+                <TrayIcon.Menu>
+                    <NativeMenu>
+                        <NativeMenuItem Header="Show _Test Window" Command="{Binding ShowWindowCommand}" />
+                    </NativeMenu>
+                </TrayIcon.Menu>
+            </TrayIcon>
+        </TrayIcons>
+    </TrayIcon.Icons>
 </Application>
 </Application>

+ 16 - 0
samples/IntegrationTestApp/App.axaml.cs

@@ -1,11 +1,25 @@
+using System.Windows.Input;
+
 using Avalonia;
 using Avalonia;
+using Avalonia.Controls;
 using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Markup.Xaml;
 using Avalonia.Markup.Xaml;
+using MiniMvvm;
 
 
 namespace IntegrationTestApp
 namespace IntegrationTestApp
 {
 {
     public class App : Application
     public class App : Application
     {
     {
+        public App()
+        {
+            ShowWindowCommand = MiniCommand.Create(() =>
+            {
+                var window = new Window() { Title = "TrayIcon demo window" };
+                window.Show();
+            });
+            DataContext = this;
+        }
+
         public override void Initialize()
         public override void Initialize()
         {
         {
             AvaloniaXamlLoader.Load(this);
             AvaloniaXamlLoader.Load(this);
@@ -20,5 +34,7 @@ namespace IntegrationTestApp
 
 
             base.OnFrameworkInitializationCompleted();
             base.OnFrameworkInitializationCompleted();
         }
         }
+
+        public ICommand ShowWindowCommand { get; }
     }
     }
 }
 }

+ 1 - 0
samples/IntegrationTestApp/IntegrationTestApp.csproj

@@ -25,6 +25,7 @@
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
+    <ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 5 - 1
src/Avalonia.Controls/NativeMenuItem.cs

@@ -5,6 +5,7 @@ using Avalonia.Controls.Primitives;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Media.Imaging;
 using Avalonia.Media.Imaging;
 using Avalonia.Metadata;
 using Avalonia.Metadata;
+using Avalonia.Threading;
 using Avalonia.Utilities;
 using Avalonia.Utilities;
 
 
 namespace Avalonia.Controls
 namespace Avalonia.Controls
@@ -164,7 +165,10 @@ namespace Avalonia.Controls
 
 
         void CanExecuteChanged()
         void CanExecuteChanged()
         {
         {
-            SetCurrentValue(IsEnabledProperty, Command?.CanExecute(CommandParameter) ?? true);
+            if (!Dispatcher.UIThread.CheckAccess())
+                Dispatcher.UIThread.Invoke(() => CanExecuteChanged());
+            else
+                SetCurrentValue(IsEnabledProperty, Command?.CanExecute(CommandParameter) ?? true);
         }
         }
 
 
         public bool HasClickHandlers => Click != null;
         public bool HasClickHandlers => Click != null;