diff --git a/ILSpy/Analyzers/CopyAnalysisResultsContextMenuEntry.cs b/ILSpy/Analyzers/CopyAnalysisResultsContextMenuEntry.cs index 15727ae9c..c339a1432 100644 --- a/ILSpy/Analyzers/CopyAnalysisResultsContextMenuEntry.cs +++ b/ILSpy/Analyzers/CopyAnalysisResultsContextMenuEntry.cs @@ -24,6 +24,8 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input.Platform; +using ILSpy.AppEnv; + namespace ILSpy.Analyzers { /// @@ -65,8 +67,7 @@ namespace ILSpy.Analyzers static void TryWriteToClipboard(string payload) { - if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime lifetime - || lifetime.MainWindow?.Clipboard is not { } clipboard) + if (UiContext.Clipboard is not { } clipboard) return; // SetTextAsync is the extension method on IClipboard — needs Avalonia.Input.Platform. _ = clipboard.SetTextAsync(payload); diff --git a/ILSpy/Analyzers/CopyAnalyzerErrorContextMenuEntry.cs b/ILSpy/Analyzers/CopyAnalyzerErrorContextMenuEntry.cs index c6e924d68..86eb2040f 100644 --- a/ILSpy/Analyzers/CopyAnalyzerErrorContextMenuEntry.cs +++ b/ILSpy/Analyzers/CopyAnalyzerErrorContextMenuEntry.cs @@ -26,6 +26,8 @@ using Avalonia.Input.Platform; using ICSharpCode.ILSpy.Properties; +using ILSpy.AppEnv; + namespace ILSpy.Analyzers { /// @@ -65,8 +67,7 @@ namespace ILSpy.Analyzers static void TryWriteToClipboard(string payload) { - if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime lifetime - || lifetime.MainWindow?.Clipboard is not { } clipboard) + if (UiContext.Clipboard is not { } clipboard) return; _ = clipboard.SetTextAsync(payload); } diff --git a/ILSpy/AppEnv/UiContext.cs b/ILSpy/AppEnv/UiContext.cs new file mode 100644 index 000000000..d520c34be --- /dev/null +++ b/ILSpy/AppEnv/UiContext.cs @@ -0,0 +1,45 @@ +// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Input.Platform; + +namespace ILSpy.AppEnv +{ + /// + /// Accessors for the desktop UI context. The classic-desktop lifetime cast was repeated at every + /// dialog-owner / clipboard / shutdown call site; centralising it here keeps those short and + /// consistent. Each member returns null / no-ops on non-desktop or design-time hosts where there + /// is no main window. + /// + public static class UiContext + { + /// The desktop main window, or null when there is no classic-desktop lifetime. + public static Window? MainWindow + => (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + + /// The main window's clipboard, or null when unavailable. + public static IClipboard? Clipboard => MainWindow?.Clipboard; + + /// Requests application shutdown on the desktop lifetime; a no-op elsewhere. + public static void Shutdown() + => (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Shutdown(); + } +} diff --git a/ILSpy/Commands/FileCommands.cs b/ILSpy/Commands/FileCommands.cs index e62d131e0..397db473c 100644 --- a/ILSpy/Commands/FileCommands.cs +++ b/ILSpy/Commands/FileCommands.cs @@ -58,8 +58,7 @@ namespace ILSpy.Commands return; } - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return; @@ -106,8 +105,7 @@ namespace ILSpy.Commands { if (!CanExecute(parameter)) return; - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return; ShowAsync(owner).HandleExceptions(); @@ -138,8 +136,7 @@ namespace ILSpy.Commands public override void Execute(object? parameter) { - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return; var dlg = new Views.ManageAssemblyListsDialog(settingsService); @@ -281,8 +278,7 @@ namespace ILSpy.Commands { public override void Execute(object? parameter) { - (global::Avalonia.Application.Current?.ApplicationLifetime - as IClassicDesktopStyleApplicationLifetime)?.Shutdown(); + UiContext.Shutdown(); } } } diff --git a/ILSpy/Commands/FilePickers.cs b/ILSpy/Commands/FilePickers.cs index d9bb2cfb8..783d87a20 100644 --- a/ILSpy/Commands/FilePickers.cs +++ b/ILSpy/Commands/FilePickers.cs @@ -23,6 +23,8 @@ using System.Threading.Tasks; using global::Avalonia.Controls.ApplicationLifetimes; using global::Avalonia.Platform.Storage; +using ILSpy.AppEnv; + namespace ILSpy.Commands { /// @@ -43,8 +45,7 @@ namespace ILSpy.Commands string? defaultFileName = null, string? title = null) { - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return null; @@ -71,8 +72,7 @@ namespace ILSpy.Commands /// public static async Task PickFolderAsync(string? title = null) { - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return null; diff --git a/ILSpy/Commands/ProjectExport.cs b/ILSpy/Commands/ProjectExport.cs index 74e8a2295..5234050eb 100644 --- a/ILSpy/Commands/ProjectExport.cs +++ b/ILSpy/Commands/ProjectExport.cs @@ -28,6 +28,7 @@ using global::Avalonia.Controls.ApplicationLifetimes; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpyX.TreeView; +using ILSpy.AppEnv; using ILSpy.Docking; using ILSpy.Languages; using ILSpy.TextView; @@ -66,8 +67,7 @@ namespace ILSpy.Commands public static async Task PromptAndExportAsync(IReadOnlyList assemblies, bool solutionMode, Language language, DockWorkspace dockWorkspace, SettingsService settingsService) { - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return; diff --git a/ILSpy/Commands/SelectPdbContextMenuEntry.cs b/ILSpy/Commands/SelectPdbContextMenuEntry.cs index c1d45c242..81cb50eab 100644 --- a/ILSpy/Commands/SelectPdbContextMenuEntry.cs +++ b/ILSpy/Commands/SelectPdbContextMenuEntry.cs @@ -27,6 +27,7 @@ using Avalonia.Platform.Storage; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.ILSpy.Properties; +using ILSpy.AppEnv; using ILSpy.AssemblyTree; using ILSpy.TreeNodes; @@ -66,8 +67,7 @@ namespace ILSpy.Commands async Task ExecuteAsync(ICSharpCode.ILSpyX.LoadedAssembly assembly) { - var owner = (global::Avalonia.Application.Current?.ApplicationLifetime - as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var owner = UiContext.MainWindow; if (owner == null) return; var initialDir = Path.GetDirectoryName(assembly.FileName); diff --git a/ILSpy/TaskbarProgressService.cs b/ILSpy/TaskbarProgressService.cs index a11a65378..b225b0968 100644 --- a/ILSpy/TaskbarProgressService.cs +++ b/ILSpy/TaskbarProgressService.cs @@ -69,7 +69,7 @@ namespace ILSpy static IntPtr TryGetMainWindowHandle() { - var window = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow; + var window = AppEnv.UiContext.MainWindow; return window?.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero; }