Skip to content
25 changes: 21 additions & 4 deletions src/Wpf.Ui.Gallery/ViewModels/Windows/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public partial class MainWindowViewModel(IStringLocalizer<Translations> localize
new NavigationViewItem(nameof(ThumbRate), typeof(ThumbRatePage)),
new NavigationViewItem(nameof(SplitButton), typeof(SplitButtonPage)),
new NavigationViewItem(nameof(Slider), typeof(SliderPage)),
},
}
},
new NavigationViewItem
{
Expand Down Expand Up @@ -182,9 +182,26 @@ public partial class MainWindowViewModel(IStringLocalizer<Translations> localize
];

[ObservableProperty]
private ObservableCollection<Wpf.Ui.Controls.MenuItem> _trayMenuItems =
private ObservableCollection<object> _trayMenuItems =
[
new Wpf.Ui.Controls.MenuItem { Header = "Home", Tag = "tray_home" },
new Wpf.Ui.Controls.MenuItem { Header = "Close", Tag = "tray_close" },
new Wpf.Ui.Controls.MenuItem()
{
Header = "Home",
Tag = "tray_home",
Icon = new SymbolIcon { Symbol = SymbolRegular.Home24 }
},
new Wpf.Ui.Controls.MenuItem()
{
Header = "Settings",
Tag = "tray_settings",
Icon = new SymbolIcon { Symbol = SymbolRegular.Settings24 }
},
new Separator(),
new Wpf.Ui.Controls.MenuItem()
{
Header = "Close",
Tag = "tray_close",
Icon = new SymbolIcon { Symbol = SymbolRegular.Dismiss24 }
},
];
}
93 changes: 93 additions & 0 deletions src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ IContentDialogService contentDialogService
snackbarService.SetSnackbarPresenter(SnackbarPresenter);
navigationService.SetNavigationControl(NavigationView);
contentDialogService.SetDialogHost(RootContentDialog);
SetupTrayMenuEvents();
}

public MainWindowViewModel ViewModel { get; }
Expand All @@ -38,6 +39,98 @@ IContentDialogService contentDialogService

private bool _isPaneOpenedOrClosedFromCode;

private void SetupTrayMenuEvents()
{
foreach (var menuItem in ViewModel.TrayMenuItems)
{
if (menuItem is MenuItem item)
{
item.Click += OnTrayMenuItemClick;
}
}
}

private void OnTrayMenuItemClick(object sender, RoutedEventArgs e)
{
if (sender is not Wpf.Ui.Controls.MenuItem menuItem)
{
return;
}

var tag = menuItem.Tag?.ToString() ?? string.Empty;

Debug.WriteLine($"System Tray Click: {menuItem.Header}, Tag: {tag}");

switch (tag)
{
case "tray_home":
HandleTrayHomeClick();
break;
case "tray_settings":
HandleTraySettingsClick();
break;
case "tray_close":
HandleTrayCloseClick();
break;
default:
if (!string.IsNullOrEmpty(tag))
{
System.Diagnostics.Debug.WriteLine($"unknown Tag: {tag}");
}

break;
}
}

private void HandleTrayHomeClick()
{
System.Diagnostics.Debug.WriteLine("Tray menu - Home Click");

ShowAndActivateWindow();

NavigateToPage(typeof(DashboardPage));
}

private void HandleTraySettingsClick()
{
System.Diagnostics.Debug.WriteLine("Tray menu - Settings Click");

ShowAndActivateWindow();

NavigateToPage(typeof(SettingsPage));
}

private static void HandleTrayCloseClick()
{
System.Diagnostics.Debug.WriteLine("Tray menu - Close Click");

Application.Current.Shutdown();
}

private void ShowAndActivateWindow()
{
if (WindowState == WindowState.Minimized)
{
SetCurrentValue(WindowStateProperty, WindowState.Normal);
}

Show();
_ = Activate();
_ = Focus();
}

private void NavigateToPage(Type pageType)
{
try
{
NavigationView.Navigate(pageType);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"NavigateToPage {pageType.Name} Error: {ex.Message}");
}
}

private void OnNavigationSelectionChanged(object sender, RoutedEventArgs e)
{
if (sender is not Wpf.Ui.Controls.NavigationView navigationView)
Expand Down
30 changes: 28 additions & 2 deletions src/Wpf.Ui.Tray/Controls/NotifyIcon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ public NotifyIcon()
internalNotifyIconManager = new Wpf.Ui.Tray.Internal.InternalNotifyIconManager();

RegisterHandlers();

// Listen for DataContext changes to update ContextMenu
DataContextChanged += OnDataContextChanged;
}

/// <summary>
Expand Down Expand Up @@ -363,6 +366,9 @@ protected virtual void Dispose(bool disposing)

System.Diagnostics.Debug.WriteLine($"INFO | {typeof(NotifyIcon)} disposed.", "Wpf.Ui.NotifyIcon");

// Clean up event handlers
DataContextChanged -= OnDataContextChanged;

Unregister();

internalNotifyIconManager.Dispose();
Expand All @@ -375,6 +381,13 @@ protected virtual void Dispose(bool disposing)
protected virtual void OnMenuChanged(ContextMenu contextMenu)
{
internalNotifyIconManager.ContextMenu = contextMenu;

// Set the DataContext for ContextMenu to enable binding
if (contextMenu.DataContext == null && DataContext != null)
{
contextMenu.DataContext = DataContext;
}

internalNotifyIconManager.ContextMenu.SetCurrentValue(Control.FontSizeProperty, MenuFontSize);
}

Expand Down Expand Up @@ -410,7 +423,6 @@ private static void OnFocusOnLeftClickChanged(DependencyObject d, DependencyProp
if (e.NewValue is not bool newValue)
{
notifyIcon.FocusOnLeftClick = false;

return;
}

Expand All @@ -427,7 +439,6 @@ private static void OnMenuOnRightClickChanged(DependencyObject d, DependencyProp
if (e.NewValue is not bool newValue)
{
notifyIcon.MenuOnRightClick = false;

return;
}

Expand Down Expand Up @@ -455,6 +466,12 @@ private void InitializeIcon()
internalNotifyIconManager.Icon = Icon;
internalNotifyIconManager.MenuOnRightClick = MenuOnRightClick;
internalNotifyIconManager.FocusOnLeftClick = FocusOnLeftClick;

// Add Menu initialization
if (Menu != null)
{
OnMenuChanged(Menu);
}
}

private void RegisterHandlers()
Expand All @@ -466,4 +483,13 @@ private void RegisterHandlers()
internalNotifyIconManager.MiddleClick += OnMiddleClick;
internalNotifyIconManager.MiddleDoubleClick += OnMiddleDoubleClick;
}

private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// Update ContextMenu DataContext when NotifyIcon DataContext changes
if (Menu != null && e.NewValue != null)
{
Menu.DataContext = e.NewValue;
}
}
}
5 changes: 4 additions & 1 deletion src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ protected virtual void OpenMenu()

// Without setting the handler window at the front, menu may appear behind the taskbar
_ = Interop.User32.SetForegroundWindow(HookWindow.Handle);
ContextMenuService.SetPlacement(ContextMenu, PlacementMode.MousePoint);

// Set placement properties for better positioning
ContextMenu.SetCurrentValue(ContextMenu.PlacementProperty, PlacementMode.MousePoint);
ContextMenu.SetCurrentValue(ContextMenu.PlacementTargetProperty, null);

// ContextMenu.ApplyMica();
ContextMenu.SetCurrentValue(ContextMenu.IsOpenProperty, true);
Expand Down