必要に駆られてタスクトレイに常駐するアプリを作ることになったので、その方法について画像とソースコードを交えて解説したいと思います。
アイコンの入手方法、Visual Studio側の参照設定を含め、全体的に網羅しています。
掲載するサンプルソースは、コンテキストメニューや設定画面の表示を含んでおり、タスク常駐アプリのテンプレートとしてお使い頂けるようにしました。
タスクトレイ常駐アプリの動作
ここで言うタスクトレイ常駐アプリは、下記の様にタスクトレイに常駐し、右クリックによりメニューを表示したり、設定画面を表示するようなアプリです。
WPFで作成したMainWindow が呼び出せるので、通常のWPFアプリと同じ感覚でタスクトレイ常駐アプリを作成することができます。
作成手順
タスクトレイ常駐アプリを作るには、以下の手順が必要になります。
WPFでありながらSystem.Windows.Fromを参照設定する必要があります。
これは、タスクトレイ常駐型プログラムを直接WPFがサポートしていないからです。
System.Windows.Fromを使うのはプログラムが最初に起動する部分(App.xaml.cs)だけなので、設定画面は通常通りWPFで記述できます。
アイコンの準備
一から作ってもよいのですが、この記事では、iconsets というサイトから、無料アイコンを調達しました。
今回は、こちらのアイコンを使っています。
この時、ファイル形式は ICO を選ぶ必要がありますが、サイズは何でも構いません。
私は64pxを選択しました。
プロジェクトの作成
Visual Studio 2022 でプロジェクト(WPF+Windowsアプリ+Microsoft Framework)を作成します。
今回は WinCapture というプロジェクト名(ソリューション名も同じ)にしましたが、ここは作成するアプリの内容に合わせて適宜命名して下さい。
参照の追加
ソリューションエクスプローラーから参照マネージャーを表示し、次の2つを参照設定します。
- System.Windows.Forms
- System.Drawing
アイコンにリソースを追加
ダウンロードしたアイコンファイルをソリューションエクスプローラーのプロジェクト名(今回はWinCapture)にドラッグ&ドロップします。
ドラッグ&ドロップが終わると下記のところにアイコンファイルが表示されるので、プロパティのビルドアクションが Resource になっている事を確認します。
App.xaml.cs にタスク常駐用のコードを記述
タスク常駐用コードの記述は、 App.xaml と App.zaml.cs の2つです。
今回は割愛しますが、もし設定画面を作成する場合は、MainWindow.xaml と MainWindow.xaml.cs の2つに必要なコードを記述して下さい。
App.xamlの修正
App.xaml には、アプリ起動時に呼び出される画面が指定されています。
これをこのままにしておくと、アプリ起動時に設定画面(MainWindow)が表示されてしまうので、今回は以下の部分を削除します。
StartupUri="MainWindow.xaml"
もちろん、起動時に毎回設定画面を利用者に促すのであれば、この修正は必要ありません。
この修正によりMainWindowが実行されなくなるため、常駐時に実行したい処理(何らかの監視処理)は、App.xaml.cs に記述することになります。
App.xaml.cs の追加
追加するコードは非常にシンプルで、以下の通りOnStartupメソッドと、OnExitメソッドを上書きするだけでタスクトレイに常駐させることができます。
//ソースコード先頭の下記の2行を追加
using System.Windows.Forms;
using System.Drawing;
// public partial class App : System.Windows.Applicationの中に以下を記述
//常駐終了時に開放するために保存しておく
private System.Windows.Forms.NotifyIcon _notifyIcon;
/// <summary>
/// 常駐開始時の初期化処理
/// </summary>
/// <param name="e"></param>
protected override void OnStartup(StartupEventArgs e)
{
//継承元のOnStartupを呼び出す
base.OnStartup(e);
//アイコンの取得
var icon = GetResourceStream(new Uri("codinghtml_117796.ico", UriKind.Relative)).Stream;
//通知領域にアイコンを表示
_notifyIcon = new System.Windows.Forms.NotifyIcon
{
Visible = true,
Icon = new System.Drawing.Icon(icon),
Text = "WinCapture"
};
//別タスクで監視処理を実行
Task.Run(() => /*~~監視処理~~*/);
}
/// <summary>
/// 常駐終了時の処理
/// </summary>
/// <param name="e"></param>
protected override void OnExit(ExitEventArgs e)
{
_notifyIcon.Dispose();
//継承元の終了イベントを呼び出す
base.OnExit(e);
}
これでタスクトレイに常駐し、何らかの開始処理が実行できるようになりましたが、このままでは終了することもメニューを出すこともできません。
一般的には、右クリックでメニューを表示し、そこから終了や設定画面の呼び出しを行うケースが多いので、次に紹介するサンプルプログラムでは、その部分を追加しています。
サンプルプログラムのソース
今回紹介するサンプルプログラムのソース(本記事先頭のデモ画面)は、次の機能を持っています。
- 常駐アイコンを右クリックすることで、コンテキストメニューの表示が可能
- 常駐アイコンを左クリック、またはコンテキストメニューの「設定画面」から設定画面の呼び出しが可能
- 閉じるボタンをクリックすることで設定画面を非表示化
- コンテキストメニューの「終了」を選ぶことでプログラムを完全終了
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Drawing;
// namespaceは適宜変更して下さい。
namespace WinCapture
{
//常駐終了時に開放するために保存しておく
private System.Windows.Forms.ContextMenuStrip _menu;
private System.Windows.Forms.NotifyIcon _notifyIcon;
/// <summary>
/// App.xaml の相互作用ロジック
/// </summary>
public partial class App : System.Windows.Application
{
private MainWindow _win = null; //2重起動防止用
protected override void OnStartup(StartupEventArgs e)
{
//継承元のOnStartupを呼び出す
base.OnStartup(e);
//アイコンの取得
var icon = GetResourceStream(new Uri("codinghtml_117796.ico", UriKind.Relative)).Stream;
//コンテキストメニューを作成
_menu = CreateMenu();
//通知領域にアイコンを表示
_notifyIcon = new System.Windows.Forms.NotifyIcon
{
Visible = true,
Icon = new System.Drawing.Icon(icon),
Text = "WinCapture",
ContextMenuStrip = _menu
};
//アイコンがクリックされたら設定画面を表示
notifyIcon.MouseClick += (s,er) =>
{
if (er.Button == System.Windows.Forms.MouseButtons.Left)
{
ShowMainWindow();
}
};
//別タスクで監視処理を実行
Task.Run(() => /*~~監視処理~~*/);
}
/// <summary>
/// 終了時の処理
/// </summary>
/// <param name="e"></param>
protected override void OnExit(ExitEventArgs e)
{
_menu.Dispose();
_notifyIcon.Dispose();
base.OnExit(e);
}
/// <summary>
/// 設定画面を表示
/// </summary>
private void ShowMainWindow()
{
if (_win == null)
{
_win = new MainWindow();
//ウィンドウを画面中央に表示
_win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
//Windowsを表示する
_win.Show();
//閉じるボタンが押された時のイベント処理を登録
_win.Closing += (s,e) =>
{
_win.Hide(); //非表示にする
e.Cancel = true; //閉じるをキャンセルする
};
}
else
{
//Windowsを表示する
_win.Show();
}
}
/// <summary>
/// コンテキストメニューの表示
/// </summary>
/// <returns></returns>
private ContextMenuStrip CreateMenu()
{
var menu = new System.Windows.Forms.ContextMenuStrip();
menu .Items.Add("各種設定", null, (s, e) => { ShowMainWindow(); });
menu .Items.Add("WinCaptureを終了", null, (s, e) => { Shutdown(); });
return menu ;
}
}
}
このサンプルソースを元にコンテキストメニューに必要な機能を記述し、MainWindow.xaml 、MainWindow.xaml.cs に設定画面の機能を実装すれば、オリジナルのタスクトレイ常駐型アプリが完成です。
まとめ
今回は WPF を使ったタスクトレイ常駐型アプリの作り方について、
- アイコンの入手方法
- 必要な参照設定
- タスクトレイに常駐させるためのソースコードの解説
の説明と、コンテキストメニューや設定画面の呼び出し機能を持ったサンプルプログラムの紹介
を行いました。
タスクトレイ常駐型アプリと聞くと、なんか難しいことをする必要があるんじゃないかと思われる方が多いかもしれません。
しかし、ここで紹介した通り非常に簡単に作成することができます。
タスクトレイ常駐は何らかの監視をするようなアプリを作成する際に便利なので、もし機会があれば一度お試し下さい。
この記事が皆様のプログラミングの一助になれば幸いです。
コメント