首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# WinForms 最小化至系統通知區 (System Tray) 完整實作

     編輯:關於C語言

需求

  • 視窗最小化時隱藏至工作列通知區 (系統托盤),不佔用工作列空間。
  • 托盤圖示右鍵選單提供「開啟」、「退出」功能。
  • 雙擊托盤圖示還原視窗。
  • 應用程式關閉時正確釋放托盤圖示資源。

核心元件

  • NotifyIcon:系統托盤圖示元件 (元件工具箱 → Common Controls)
  • ContextMenuStrip:右鍵選單
  • 表單事件:Resize、FormClosing、Load

完整程式碼

public partial class MainForm : Form
{
    private NotifyIcon _trayIcon;
    private ContextMenuStrip _trayMenu;

    public MainForm()
    {
        InitializeComponent();
        InitializeTrayIcon();
    }

    private void InitializeTrayIcon()
    {
        // 1. 建立右鍵選單
        _trayMenu = new ContextMenuStrip();
        _trayMenu.Items.Add("開啟主視窗", null, (s, e) => ShowWindow());
        _trayMenu.Items.Add("退出", null, (s, e) => ExitApplication());

        // 2. 建立 NotifyIcon
        _trayIcon = new NotifyIcon
        {
            Icon = this.Icon ?? SystemIcons.Application, // 使用表單圖示或預設
            Text = "我的應用程式",
            Visible = false, // 預設隱藏,最小化時顯示
            ContextMenuStrip = _trayMenu
        };

        // 3. 雙擊圖示還原視窗
        _trayIcon.DoubleClick += (s, e) => ShowWindow();

        // 4. 表單事件訂閱
        this.Resize += MainForm_Resize;
        this.FormClosing += MainForm_FormClosing;
        this.Load += MainForm_Load;
    }

    private void MainForm_Load(object sender, EventArgs e)
    {
        // 確保圖示資源已載入
        if (_trayIcon.Icon == null && this.Icon != null)
            _trayIcon.Icon = this.Icon;
    }

    private void MainForm_Resize(object sender, EventArgs e)
    {
        if (this.WindowState == FormWindowState.Minimized)
        {
            this.Hide(); // 隱藏視窗與工作列按鈕
            _trayIcon.Visible = true; // 顯示托盤圖示
            _trayIcon.ShowBalloonTip(1000, "最小化至托盤", "程式仍在背景執行", ToolTipIcon.Info);
        }
    }

    private void ShowWindow()
    {
        this.Show();
        this.WindowState = FormWindowState.Normal;
        this.Activate(); // 取得焦點
        _trayIcon.Visible = false;
    }

    private void ExitApplication()
    {
        _trayIcon.Visible = false; // 先隱藏圖示,避免殘留
        _trayIcon.Dispose(); // 釋放非受控資源
        Application.Exit(); // 結束訊息迴圈
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        // 若使用者點右上角 X,預設關閉應用程式
        // 若想改為最小化至托盤,取消註解下列兩行並註解 ExitApplication() 呼叫:
        // if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; this.WindowState = FormWindowState.Minimized; }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _trayIcon?.Dispose();
            _trayMenu?.Dispose();
        }
        base.Dispose(disposing);
    }
}

進階功能擴充

1. 自訂托盤圖示動畫 / 狀態指示


private readonly Icon[] _animationIcons = new Icon[8]; // 載入 8 幀圖示
private int _animIndex = 0;
private System.Windows.Forms.Timer _animTimer;

private void StartAnimation()
{
    _animTimer = new System.Windows.Forms.Timer { Interval = 100 };
    _animTimer.Tick += (s, e) =>
    {
        _trayIcon.Icon = _animationIcons[_animIndex++ % _animationIcons.Length];
    };
    _animTimer.Start();
}

private void StopAnimation()
{
    _animTimer?.Stop();
    _trayIcon.Icon = this.Icon; // 恢復預設
}

2. 氣球提示 (Balloon Tip) 事件處理


_trayIcon.BalloonTipClicked += (s, e) => ShowWindow(); // 點擊氣球提示還原
_trayIcon.BalloonTipClosed += (s, e) => { /* 記錄關閉原因 e.CloseReason */ };

3. 單一實例應用程式 (配合 Mutex)


static class Program
{
    [STAThread]
    static void Main()
    {
        using var mutex = new Mutex(true, "Global\\MyUniqueAppId", out bool createdNew);
        if (!createdNew)
        {
            // 已有實例執行中,傳送訊息喚醒或直接返回
            MessageBox.Show("程式已在執行中", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            return;
        }
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

常見問題與解決

問題原因解決
托盤圖示不顯示Icon 屬性為 null、Visible=false、DPI 縮放導致圖示過小指派有效 .ico、確保 Visible=true、提供多尺寸圖示 (16/32/48/256px)
關閉視窗後托盤圖示殘留 (鬼影)未在 FormClosing/Dispose 呼叫 _trayIcon.Visible = false; _trayIcon.Dispose();確實釋放資源,參考上方 Dispose 模式
雙擊圖示無反應未訂閱 DoubleClick 事件、或被 ContextMenuStrip 攔截確認事件註冊、ContextMenuStrip 不會吞噬雙擊
最小化後無法還原this.Show() 前未設定 WindowState = Normal依序呼叫 Show() → WindowState = Normal → Activate()
高 DPI 模糊圖示解析度不足在 .ico 內內建 256x256 PNG 壓縮格式,Windows 10/11 自動選用

WPF / .NET Core 3.0+ 專案注意事項

  • NotifyIcon 屬於 System.Windows.Forms,WPF 專案需參考 System.Windows.Forms.dll。
  • .NET Core / .NET 5+ 需在專案檔加入 <UseWindowsForms>true</UseWindowsForms>。
  • WPF 原生替代方案:Hardcodet.Wpf.TaskbarNotification (NuGet),純 WPF 實作、支援 MVVM、豐富動畫/樣式。

最佳實務清單

  • [ ] 表單圖示 (this.Icon) 設定有效 .ico 檔案 (含 16x16, 32x32, 48x48, 256x256)
  • [ ] NotifyIcon.Visible 預設 false,最小化時設 true,還原/結束時設 false
  • [ ] Dispose 釋放 NotifyIcon、ContextMenuStrip、Timer
  • [ ] 提供右鍵選單「開啟」、「退出」,雙擊圖示還原
  • [ ] 單一實例保護 (Mutex) 避免多開
  • [ ] 應用程式真正退出時呼叫 Application.Exit() 而非 Environment.Exit()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved