using System; using System.Collections.Specialized; using System.ComponentModel; using System.Drawing; using System.Globalization; using System.Windows; using System.Windows.Data; using System.Windows.Forms; using System.Windows.Interop; using PersonalToolBox.Helpers; using PersonalToolBox.ViewModels; namespace PersonalToolBox.Views; public partial class MainWindow : Window { private readonly MainViewModel _viewModel; private readonly HotKeyManager _hotKeyManager; private NotifyIcon? _notifyIcon; private bool _canActuallyClose; public MainWindow(MainViewModel viewModel, HotKeyManager hotKeyManager) { InitializeComponent(); _viewModel = viewModel; _hotKeyManager = hotKeyManager; DataContext = viewModel; viewModel.Logs.CollectionChanged += OnLogsCollectionChanged; CreateTrayIcon(); } /// /// 窗口句柄就绪后注册全局快捷键 /// protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); var hwndSource = (HwndSource)PresentationSource.FromVisual(this)!; _hotKeyManager.Initialize(hwndSource.Handle); hwndSource.AddHook(WndProcHook); _viewModel.RegisterAllHotKeys(); } // ──────────────── 系统托盘 ──────────────── /// /// 创建系统托盘图标及右键菜单 /// private void CreateTrayIcon() { _notifyIcon = new NotifyIcon { Icon = CreateAppIcon(), Visible = true, Text = "个人工具箱" }; _notifyIcon.MouseClick += (s, e) => { if (e.Button == MouseButtons.Left) ToggleVisibility(); }; var menu = new ContextMenuStrip(); menu.Items.Add("显示主界面", null, (_, _) => ShowMainWindow()); menu.Items.Add("设置", null, (_, _) => OpenSettings()); menu.Items.Add(new ToolStripSeparator()); menu.Items.Add("彻底退出", null, (_, _) => ExitApplication()); _notifyIcon.ContextMenuStrip = menu; } /// /// 程序化生成 32x32 托盘图标 /// private static System.Drawing.Icon CreateAppIcon() { var bmp = new System.Drawing.Bitmap(32, 32); using var g = System.Drawing.Graphics.FromImage(bmp); g.Clear(System.Drawing.Color.FromArgb(30, 30, 46)); using var font = new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 16, System.Drawing.FontStyle.Bold); using var brush = new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(137, 180, 250)); g.DrawString("T", font, brush, new System.Drawing.PointF(6, 3)); return System.Drawing.Icon.FromHandle(bmp.GetHicon()); } /// /// 左键托盘图标:切换窗口显示/隐藏 /// private void ToggleVisibility() { if (IsVisible) Hide(); else ShowMainWindow(); } /// /// 显示主窗口并置前 /// private void ShowMainWindow() { Show(); WindowState = WindowState.Normal; Activate(); } /// /// 打开设置(当前无额外设置界面,提示使用内置功能) /// private void OpenSettings() { ShowMainWindow(); _viewModel.LogServiceMessage("设置功能可通过左侧栏管理分类和主题切换"); } /// /// 彻底退出程序 /// public void ExitApplication() { _canActuallyClose = true; _notifyIcon?.Dispose(); _hotKeyManager.Dispose(); System.Windows.Application.Current.Shutdown(); } /// /// 点击关闭按钮时隐藏窗口而非退出 /// protected override void OnClosing(CancelEventArgs e) { if (!_canActuallyClose) { e.Cancel = true; Hide(); } base.OnClosing(e); } // ──────────────── 其他 ──────────────── private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { handled = _hotKeyManager.TryHandleMessage(msg, wParam, lParam); return IntPtr.Zero; } private void OnLogsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add && LogListBox.Items.Count > 0) { Dispatcher.BeginInvoke(new Action(() => { LogListBox.ScrollIntoView(LogListBox.Items[^1]); }), System.Windows.Threading.DispatcherPriority.Background); } } } /// /// bool → double: true=1.0, false=0.4 (工具卡片失效时置灰) /// public class BoolToOpacityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is bool b && b ? 1.0 : 0.4; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); } /// /// string → string: 取字符串首字符作为图标占位 /// public class FirstCharConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var s = value as string; return string.IsNullOrEmpty(s) ? "?" : s[0].ToString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); }