WPF アプリの起動・終了処理
WPF アプリの多重起動防止や、アプリ設定の読み込みなどではまったのでメモ。
Visual Studio で WPF アプリのプロジェクトを生成すると、以下の 4 ファイルが生成される。
- App.xaml
- App.xaml.cs
- Window1.xaml
- Window1.xaml.cs
これらは XAML + コードビハインドという組み合わせになっており App
がアプリケーション全体、Window1 はメイン ウィンドウを表す。WinForm
時代と異なりエントリ ポイントとなる Main
メソッドは隠蔽されている。また App.xaml.cs を開いても Window1
クラスのインスタンス作成や起動処理などは書かれていない。
ではどのように Window1
を表示しているのか。App.xaml を開くと、その先頭部分に回答がある。
<Application
x:Class="Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
StartupUri
によってアプリの起動時に自動表示されるウィンドウを指定している。アプリの多重起動チェックや前回値の読み込みなどを行う場合はこれが邪魔になるから、この記事では独自に起動処理実装することにした。
起動と終了のハンドリング
多重起動チェックやアプリ設定の読み書き処理はアプリの起動・終了時が望ましいため、これをハンドリングする。また多重起動を確認したときはウィンドウを表示せずに終了するため App.xaml から StartupUri
を削除する。
<Application
x:Class="Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
ついでにメインウィンドウ クラスの名前が Window1
というのは分かりにくいので MainWindow
という名前に変更しておく。関連ファイルも MainWindow.xaml と MainWindowxaml.cs へ修正。
次に App.xaml.cs を開き OnStartup
と OnExit
をオーバーライド。多重起動チェック用の Mutex
もフィールドに定義しておく。
namespace Test
{
/// <summary>
/// App.xaml の相互作用ロジック
/// </summary>
public partial class App : Application
{
/// <summary>
/// アプリケーションが終了する時のイベント。
/// </summary>
/// <param name="e">イベント データ。</param>
protected override void OnExit(ExitEventArgs e)
{
}
/// <summary>
/// アプリケーションが開始される時のイベント。
/// </summary>
/// <param name="e">イベント データ。</param>
protected override void OnStartup(StartupEventArgs e)
{
}
/// <summary>
/// 多重起動を防止する為のミューテックス。
/// </summary>
private static Mutex _mutex;
}
}
このままでは起動しても何も表示されないので OnStartup
に以下の実装を行う。
protected override void OnStartup(StartupEventArgs e)
{
// 多重起動チェック
App._mutex = new Mutex(false, "Test-{C9386A33-46F3-072b-86C4-5BF04D0A0235}");
if (!App._mutex.WaitOne(0, false))
{
App._mutex.Close();
App._mutex = null;
this.Shutdown();
return;
}
// ここでアプリケーション初期化
// メイン ウィンドウ表示
MainWindow window = new MainWindow();
window.Show();
}
Mutex
コンストラクタに指定する文字列は、多重起動チェックにおいて他アプリと競合しないように GUID を指定する。重複回避としてはこれで十分だが、私は念のためにアプリ名も入れておく。Visual Studio のインストール フォルダを $
とすると $\Common7\Tools
というフォルダに guidgen.exe という名前のツールがあり、これで GUID を生成できる。
Mutex
を検出したときは先に起動しているアプリがあるので、すぐにプロセスを終了する。このチェックを通過したならメインウィンドウを表示する。
// メイン ウィンドウ表示
MainWindow window = new MainWindow();
window.Show();
メインウィンドウは OnStartup
内でインスタンスを生成して表示する。インスタンスをフィールドとして保持する必要はない。
「ここでアプリケーション初期化」とコメントした箇所は MainWndow
が使用するデータの設定部である。MVVM で設計して ViewModel クラスを作成しているなら、ここで関連づけておく。設定は MainWindow
クラスで処理してもよいが、例えば前回の終了状態などはアプリ設定として記録する事が多いだろう。よってアプリ全体を表す App
クラスで設定した方が設計的に好ましい。
起動処理が実装されたので次は終了処理を実装。オーバーライドした OnExit の中身を定義しよう。
protected override void OnExit( ExitEventArgs e )
{
if (App._mutex == null) { return; }
// アプリケーション設定の保存
// ミューテックスの解放
App._mutex.ReleaseMutex();
App._mutex.Close();
App._mutex = null;
}
OnStartup
で多重起動と判定されたら Sutdown
メソッドによりアプリを終了しているのだが、ここでも OnExit
が呼び出される。そのため Mutex
の null チェックを実行して余計な終了処理が走らないようにしている。
アプリ設定の保存は Settings
クラスなどを使用する事になるだろう。例えば Settings.Default.Save
メソッドを呼び出す。
すべての処理が完了したら Mutex
を解放し、アプリ全体の終了とする。