Phase 5: tray icon with minimize-to-tray and context menu

GUI csproj enables UseWindowsForms (NotifyIcon lives in WinForms even
in .NET 8). New Services/TrayIcon.cs wraps NotifyIcon with a context
menu (Open / Restart service / Exit) and the embedded webhook-server
icon. MainWindow creates the TrayIcon, hides itself on minimize and
restores on tray double-click.

Adds GlobalUsings.cs to alias the WPF defaults for types that exist
in both WPF and WinForms (Application, MessageBox, TextBox, Binding,
etc.) so existing code keeps compiling without per-file changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 09:51:00 -04:00
parent f3bca1e8ff
commit 9525ee358e
6 changed files with 132 additions and 12 deletions
+28 -3
View File
@@ -8,12 +8,37 @@ namespace WebhookServer.Gui;
public partial class MainWindow : Window
{
private readonly TrayIcon _tray;
private readonly MainViewModel _vm;
public MainWindow()
{
InitializeComponent();
var vm = new MainViewModel(new AdminPipeClient());
DataContext = vm;
Loaded += async (_, _) => await vm.RefreshCommand.ExecuteAsync(null);
_vm = new MainViewModel(new AdminPipeClient());
DataContext = _vm;
_tray = new TrayIcon(
resolveMainWindow: () => Application.Current.MainWindow,
restartServiceAsync: async () => await new AdminPipeClient().RestartListenerAsync());
Loaded += async (_, _) => await _vm.RefreshCommand.ExecuteAsync(null);
StateChanged += OnStateChanged;
Closed += (_, _) => _tray.Dispose();
}
private void OnStateChanged(object? sender, EventArgs e)
{
// Minimize-to-tray: hide the window when the user minimizes; restoring is
// via the tray icon's double-click or context menu.
if (WindowState == WindowState.Minimized)
{
Hide();
ShowInTaskbar = false;
}
else
{
ShowInTaskbar = true;
}
}
private void OnLogTailChanged(object sender, TextChangedEventArgs e)