アプリに通知アイコンを追加しましたが、システム トレイに通知アイコンのコピーが 3 つまで表示されることがよくあります。これには理由がありますか?
それが起こらないようにする方法はありますか。
多くの場合、これはアプリが閉じられた後も持続し、システムトレイに移動してシステムトレイが展開して折りたたまれ、すべてが消えるまで続きます。
これはアプリケーションのデバッグ中ですか? その場合、システム トレイからアイコンを削除するメッセージは、アプリケーションが正常に終了した場合にのみ送信され、例外が原因で終了した場合、または Visual Studio から終了した場合にのみ、アイコンがマウスオーバーされるまで残ります。
親 Window の Closed イベントを使用してアイコンを強制終了できます。これは、Visual Studio (私の場合は 2010) でテストする場合でも、私の WPF アプリで機能します。
parentWindow.Closing += (object sender, CancelEventArgs e) =>
{
notifyIcon.Visible = false;
notifyIcon.Icon = null;
notifyIcon.Dispose();
};
私がしたこと:
システム トレイを更新するクラス ライブラリを作成します。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SystrayUtil
{
internal enum MessageEnum
{
WM_MOUSEMOVE = 0x0200,
WM_CLOSE = 0x0010,
}
internal struct RECT
{
internal int Left;
internal int Top;
internal int Right;
internal int Bottom;
internal RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
}
public sealed class Systray
{
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, IntPtr lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, int message, uint wParam, long lParam);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetClientRect(IntPtr hWnd, out RECT usrTray);
public static void Cleanup()
{
RECT sysTrayRect = new RECT();
IntPtr sysTrayHandle = FindWindow("Shell_TrayWnd", null);
if (sysTrayHandle != IntPtr.Zero)
{
IntPtr childHandle = FindWindowEx(sysTrayHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
if (childHandle != IntPtr.Zero)
{
childHandle = FindWindowEx(childHandle, IntPtr.Zero, "SysPager", IntPtr.Zero);
if (childHandle != IntPtr.Zero)
{
childHandle = FindWindowEx(childHandle, IntPtr.Zero, "ToolbarWindow32", IntPtr.Zero);
if (childHandle != IntPtr.Zero)
{
bool systrayWindowFound = GetClientRect(childHandle, out sysTrayRect);
if (systrayWindowFound)
{
for (int x = 0; x < sysTrayRect.Right; x += 5)
{
for (int y = 0; y < sysTrayRect.Bottom; y += 5)
{
SendMessage(childHandle, (int)MessageEnum.WM_MOUSEMOVE, 0, (y << 16) + x);
}
}
}
}
}
}
}
}
}
}
dll をコピーします。"%ProgramFiles%\Microsoft Visual Studio x.x\Common7\IDE\PublicAssemblies\SystrayUtil.dll"
xx は Visual Studio のバージョン番号です。
マクロを記録して保存する
マクロを編集する
作成した dll への参照を追加します。
Imports SystrayUtil
Module EnvironmentEvents の上部にあるインポートのリストに追加します。
不要なアイテムを削除し、次のコードを EnvironmentEvents モジュールに追加します。
Public Sub DebuggerEvents_OnEnterDesignMode(ByVal Reason As EnvDTE.dbgEventReason) Handles DebuggerEvents.OnEnterDesignMode
Systray.Cleanup()
MsgBox("Entered design mode!")
End Sub
MsgBox("Entered design mode!")
デバッグセッションから戻るたびにメッセージボックスがポップアップするのは面倒なので、うまくいく場合は削除してください。
これは、通常アプリケーションを閉じるときに機能するはずです。
// in form's constructor
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
private void OnApplicationExit(object sender, EventArgs e)
{
try
{
if (notifyIcon1!= null)
{
notifyIcon1.Visible = false;
notifyIcon1.Icon = null;
notifyIcon1.Dispose();
notifyIcon1= null;
}
}
catch { }
}
Visual Studio の停止デバッグ ボタンからアプリを停止すると、プロセスが強制終了され、破棄イベントは発生しません。