增强托盘功能和界面样式
在 `App.xaml` 中更新资源字典,添加 `MaterialTrayMenuItem.xaml` 以支持托盘菜单样式。 在 `MainWindow.xaml` 中添加 `Closed` 和 `Loaded` 事件处理程序。 在 `MainWindow.xaml.cs` 中引入 `TrayIconManager`,管理系统托盘图标及其行为。 更新 `chatclient.csproj` 中 `chat.ico` 的属性以确保复制到输出目录。 在 `MaterialTrayMenuItem.xaml` 中定义 Material Design 风格的托盘菜单项和上下文菜单样式。 创建 `TrayIconManager.cs` 类以优化托盘图标的创建和事件处理,提升用户体验。
This commit is contained in:
parent
d7e9a93bf6
commit
424311f088
@ -5,14 +5,15 @@
|
|||||||
xmlns:local="clr-namespace:chatclient"
|
xmlns:local="clr-namespace:chatclient"
|
||||||
StartupUri="MainWindow.xaml">
|
StartupUri="MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
|
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/chatclient;component/Data/MaterialTrayMenuItem.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
45
chatclient/Data/MaterialTrayMenuItem.xaml
Normal file
45
chatclient/Data/MaterialTrayMenuItem.xaml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
|
||||||
|
<!-- Material Design 托盘菜单样式 -->
|
||||||
|
<Style x:Key="MaterialTrayMenuItem" TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Padding" Value="12,8"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}"/>
|
||||||
|
<Setter Property="FontSize" Value="14"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="MenuItem">
|
||||||
|
<Border x:Name="Border"
|
||||||
|
Background="Transparent"
|
||||||
|
CornerRadius="4"
|
||||||
|
SnapsToDevicePixels="True">
|
||||||
|
<Grid>
|
||||||
|
<materialDesign:Ripple Content="{TemplateBinding Header}" Background="Transparent" Foreground="{TemplateBinding Foreground}"
|
||||||
|
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Center" Padding="{TemplateBinding Padding}"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsHighlighted" Value="True">
|
||||||
|
<Setter TargetName="Border" Property="Background" Value="{DynamicResource MaterialDesignSelection}"/>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="MaterialTrayMenu" TargetType="ContextMenu">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesignDivider}"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="Padding" Value="8"/>
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||||
|
<Setter Property="Effect">
|
||||||
|
<Setter.Value>
|
||||||
|
<DropShadowEffect BlurRadius="16" ShadowDepth="4" Color="#40000000"/>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
122
chatclient/Data/TrayIconManager.cs
Normal file
122
chatclient/Data/TrayIconManager.cs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using Hardcodet.Wpf.TaskbarNotification;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace chatclient.Data
|
||||||
|
{
|
||||||
|
public class TrayIconManager
|
||||||
|
{
|
||||||
|
private readonly TaskbarIcon _trayIcon;
|
||||||
|
private readonly Window _mainWindow;
|
||||||
|
|
||||||
|
public TrayIconManager(Window mainWindow)
|
||||||
|
{
|
||||||
|
_mainWindow = mainWindow;
|
||||||
|
|
||||||
|
// 创建托盘图标
|
||||||
|
_trayIcon = new TaskbarIcon
|
||||||
|
{
|
||||||
|
Icon = new System.Drawing.Icon("resource/chat.ico"),
|
||||||
|
ToolTipText = "Material Design Application",
|
||||||
|
ContextMenu = CreateContextMenu()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 注册事件
|
||||||
|
_trayIcon.TrayMouseDoubleClick += TrayIcon_TrayMouseDoubleClick;
|
||||||
|
_mainWindow.Closing += MainWindow_ClosingHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_ClosingHandler(object? sender, System.ComponentModel.CancelEventArgs e)
|
||||||
|
{
|
||||||
|
// 取消关闭操作,改为最小化到托盘
|
||||||
|
e.Cancel = true;
|
||||||
|
_mainWindow.Hide();
|
||||||
|
|
||||||
|
// 显示通知
|
||||||
|
//_trayIcon.ShowBalloonTip("Application minimized",
|
||||||
|
// "The application is running in the system tray",
|
||||||
|
// BalloonIcon.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContextMenu CreateContextMenu()
|
||||||
|
{
|
||||||
|
// 创建Material Design风格的上下文菜单
|
||||||
|
var contextMenu = new ContextMenu
|
||||||
|
{
|
||||||
|
Style = (Style)Application.Current.Resources["MaterialTrayMenu"]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加菜单项
|
||||||
|
contextMenu.Items.Add(CreateMenuItem("Open Application", PackIconKind.WindowRestore, OpenApp_Click));
|
||||||
|
contextMenu.Items.Add(CreateMenuItem("Settings", PackIconKind.Cog, Settings_Click));
|
||||||
|
contextMenu.Items.Add(new Separator { Style = (Style)Application.Current.Resources["MaterialDesignLightSeparator"] });
|
||||||
|
contextMenu.Items.Add(CreateMenuItem("Check for Updates", PackIconKind.Update, Updates_Click));
|
||||||
|
contextMenu.Items.Add(CreateMenuItem("Help", PackIconKind.HelpCircle, Help_Click));
|
||||||
|
contextMenu.Items.Add(new Separator { Style = (Style)Application.Current.Resources["MaterialDesignLightSeparator"] });
|
||||||
|
contextMenu.Items.Add(CreateMenuItem("Exit", PackIconKind.Power, Exit_Click));
|
||||||
|
|
||||||
|
return contextMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MenuItem CreateMenuItem(string header, PackIconKind iconKind, RoutedEventHandler clickHandler)
|
||||||
|
{
|
||||||
|
var menuItem = new MenuItem
|
||||||
|
{
|
||||||
|
Header = header,
|
||||||
|
Style = (Style)Application.Current.Resources["MaterialTrayMenuItem"],
|
||||||
|
Icon = new PackIcon { Kind = iconKind, Width = 20, Height = 20 }
|
||||||
|
};
|
||||||
|
|
||||||
|
menuItem.Click += clickHandler;
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TrayIcon_TrayMouseDoubleClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
RestoreApplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenApp_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
RestoreApplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestoreApplication()
|
||||||
|
{
|
||||||
|
_mainWindow.Show();
|
||||||
|
_mainWindow.WindowState = WindowState.Normal;
|
||||||
|
_mainWindow.Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Settings_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 实现设置逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Updates_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 实现更新检查逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Help_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 实现帮助逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Exit_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 释放托盘图标资源
|
||||||
|
Dispose();
|
||||||
|
Application.Current.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_trayIcon.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" x:Class="chatclient.MainWindow"
|
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" x:Class="chatclient.MainWindow"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="ChatWindow" Height="450" Width="800" MinHeight="240" MinWidth="380"
|
Title="ChatWindow" Height="450" Width="800" MinHeight="240" MinWidth="380"
|
||||||
Style="{StaticResource MaterialDesignWindow}">
|
Style="{StaticResource MaterialDesignWindow}" Closed="MainWindow_Closed" Loaded="MainWindow_Loaded">
|
||||||
<Grid>
|
<Grid>
|
||||||
<materialDesign:Card>
|
<materialDesign:Card>
|
||||||
<TabControl VerticalContentAlignment="Bottom" materialDesign:ColorZoneAssist.Mode="PrimaryMid" Style="{StaticResource MaterialDesignNavigationRailTabControl}">
|
<TabControl VerticalContentAlignment="Bottom" materialDesign:ColorZoneAssist.Mode="PrimaryMid" Style="{StaticResource MaterialDesignNavigationRailTabControl}">
|
||||||
|
@ -56,6 +56,7 @@ namespace chatclient
|
|||||||
{
|
{
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(UpdateName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(UpdateName));
|
||||||
}
|
}
|
||||||
|
private TrayIconManager? _trayManager;
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -84,6 +85,8 @@ namespace chatclient
|
|||||||
MessageScroller.ScrollToEnd();
|
MessageScroller.ScrollToEnd();
|
||||||
}), DispatcherPriority.ContextIdle);
|
}), DispatcherPriority.ContextIdle);
|
||||||
};
|
};
|
||||||
|
//Loaded += MainWindow_Loaded;
|
||||||
|
//Closed += MainWindow_Closed;
|
||||||
}
|
}
|
||||||
public static void StartReceive()
|
public static void StartReceive()
|
||||||
{
|
{
|
||||||
@ -325,5 +328,18 @@ namespace chatclient
|
|||||||
Task.Factory.StartNew(() => messageQueue.Enqueue(message));
|
Task.Factory.StartNew(() => messageQueue.Enqueue(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 初始化托盘管理器
|
||||||
|
_trayManager = new TrayIconManager(this);
|
||||||
|
}
|
||||||
|
private void MainWindow_Closed(object sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
// 清理资源
|
||||||
|
Client?.Shutdown(SocketShutdown.Both);
|
||||||
|
Client?.Close();
|
||||||
|
Client?.Dispose();
|
||||||
|
_trayManager?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="resource\chat.ico" />
|
<Content Include="resource\chat.ico">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user