WPF アプリケーションには、画面を表す Window とは別に、アプリケーション全体を管理するためのクラスがあります。
それが System.Windows.Application クラスです。
Application は、WPF アプリケーションの起動、終了、メインウィンドウ、開いているウィンドウ一覧、アプリケーション全体で共有するリソースなどを管理します。
この記事では、Application クラスの役割と主要プロパティ、コードによる構築方法、Windows コレクションの列挙方法を整理します。
Application クラスとは
Application クラスは、WPF アプリケーション全体を表すオブジェクトです。
WPF アプリケーションでは、通常 1 つのプロセスにつき 1 つの Application オブジェクトを作成します。このオブジェクトが、アプリケーションの実行ループを開始し、ウィンドウの管理や終了処理を担当します。
もっとも重要な役割は次の 3 つです。
- アプリケーションの開始と終了を管理する
- メインウィンドウや開いているウィンドウを管理する
- アプリケーション全体で共有する状態やリソースを保持する
たとえば、WPF アプリケーションでは次のように Application オブジェクトを作成し、Run メソッドでアプリケーションを開始できます。
using System;
using System.Windows;
class MyApp : Application
{
[STAThread]
static void Main(string[] args)
{
MyApp app = new MyApp();
app.Run();
}
}
Run を呼び出すと、WPF のメッセージループが開始されます。これにより、ウィンドウの表示、マウスやキーボード入力、描画、イベント処理などが継続的に処理されます。
主なプロパティ
Application クラスには、アプリケーション全体の状態を扱うためのプロパティが用意されています。
| プロパティ | 意味 |
|---|---|
Current |
現在実行中の Application オブジェクトを取得する |
MainWindow |
アプリケーションのメインウィンドウを取得または設定する |
Properties |
アプリケーション全体で共有できるキーと値のコレクション |
StartupUri |
起動時に自動的に表示する XAML ファイルの URI |
Windows |
現在開かれている WPF ウィンドウのコレクション |
それぞれの役割を見ていきます。
Current
Current は、現在実行中の Application オブジェクトを取得するための静的プロパティです。
Application app = Application.Current;
アプリケーション内の別のクラスから、現在の Application にアクセスしたいときに使います。
たとえば、どこかの処理からメインウィンドウを取得したい場合は、次のように書けます。
Window mainWindow = Application.Current.MainWindow;
自分で MyApp クラスを定義している場合は、キャストして独自のプロパティやメソッドにアクセスすることもできます。
MyApp app = (MyApp)Application.Current;
ただし、Application.Current に頼りすぎると、どこからでもアプリケーション全体の状態を変更できてしまいます。便利な反面、依存関係が見えにくくなるため、使いどころは絞るのが無難です。
MainWindow
MainWindow は、アプリケーションのメインウィンドウを表します。
Application.Current.MainWindow = new MainWindow();
Application.Current.MainWindow.Show();
MainWindow は単なる「最初に表示されたウィンドウ」ではなく、アプリケーションの中心となるウィンドウとして扱われるものです。
WPF では、最初に作成された Window が自動的に MainWindow に設定されることがあります。ただし、複数のウィンドウを扱うアプリケーションでは、明示的に設定しておくと意図が分かりやすくなります。
MainWindow window = new MainWindow();
app.MainWindow = window;
window.Show();
MainWindow は、アプリケーションの終了タイミングにも関係します。既定では、最後のウィンドウが閉じられたときにアプリケーションが終了しますが、ShutdownMode を変更すると、メインウィンドウが閉じられた時点で終了するようにもできます。
app.ShutdownMode = ShutdownMode.OnMainWindowClose;
Properties
Properties は、アプリケーション全体で共有できるディクショナリです。
Application.Current.Properties["UserName"] = "Alice";
別の場所から同じキーで値を取り出せます。
if (Application.Current.Properties.Contains("UserName"))
{
string userName = (string)Application.Current.Properties["UserName"];
}
Properties は、アプリケーション全体で一時的に共有したい値を置く場所として使えます。
たとえば、起動時に解析したコマンドライン引数、ログイン中のユーザー情報、簡単な設定値などを保持できます。
ただし、何でも Properties に入れると、どこで値が設定され、どこで使われるのか分かりにくくなります。大きなアプリケーションでは、設定クラスやサービスクラスを用意して管理した方が見通しはよくなります。
StartupUri
StartupUri は、アプリケーション起動時に自動的に表示する XAML ファイルを指定するプロパティです。
app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
app.Run();
StartupUri を設定して Run を呼び出すと、WPF は指定された XAML を読み込み、対応するウィンドウやページを表示します。
WPF プロジェクトでよく見る App.xaml では、次のように StartupUri を指定します。
<Application x:Class="SampleApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
</Application>
この場合、アプリケーション起動時に MainWindow.xaml が自動的に表示されます。
一方、起動時にログイン画面を出すか、メイン画面を出すかを条件で切り替えたい場合は、StartupUri を使わず、Startup イベントで自分でウィンドウを作成することもあります。
app.Startup += (s, e) =>
{
Window window = new MainWindow();
app.MainWindow = window;
window.Show();
};
単純なアプリケーションでは StartupUri が便利です。起動時に条件分岐が必要な場合は、Startup イベントで制御する方が柔軟です。
Windows
Windows は、現在開かれている WPF の Window オブジェクトを保持するコレクションです。
WindowCollection windows = Application.Current.Windows;
アプリケーション内で開いているウィンドウを一覧したい場合に使います。
たとえば、現在開いているウィンドウのタイトルを出力するには、次のように書けます。
foreach (Window window in Application.Current.Windows)
{
Console.WriteLine(window.Title);
}
Windows コレクションには、表示中のウィンドウだけでなく、作成済みでまだ閉じられていないウィンドウが含まれます。
Application クラスをコードで構築する
WPF では、App.xaml を使って Application クラスを定義するのが一般的です。
しかし、仕組みを理解するには、コードだけで Application を構築してみると分かりやすくなります。
次の例では、MyApp クラスを Application から継承し、Main メソッドの中でアプリケーションオブジェクトを作成しています。
using System;
using System.Windows;
using System.Windows.Controls;
class MyApp : Application
{
[STAThread]
static void Main(string[] args)
{
// アプリケーションオブジェクトの作成
MyApp app = new MyApp();
// イベントの登録
app.Startup += (s, e) =>
{
Console.WriteLine("アプリケーションを開始しました。");
Window window = new Window
{
Title = "My WPF App",
Width = 400,
Height = 250,
Content = new Button
{
Content = "Hello, WPF",
Width = 120,
Height = 32
}
};
app.MainWindow = window;
window.Show();
};
app.Exit += (s, e) =>
{
Console.WriteLine($"アプリケーションを終了しました。ExitCode={e.ApplicationExitCode}");
};
// WPF のメッセージループを開始
app.Run();
}
}
このコードの流れは次の通りです。
MyAppクラスをApplicationから継承するMainメソッドに[STAThread]属性を付けるnew MyApp()でアプリケーションオブジェクトを作成するStartupやExitなどのイベントを登録するRun()を呼び出して WPF アプリケーションを開始する
[STAThread] は、WPF アプリケーションでは重要です。
WPF の UI は STA(Single Threaded Apartment)という COM のスレッドモデルを前提に動作します。そのため、エントリポイントである Main メソッドには [STAThread] を付けます。
Run() を呼び出さないと、WPF のメッセージループが開始されません。ウィンドウを表示しても、イベントや描画を継続的に処理する仕組みが動かないため、通常の WPF アプリケーションとしては成立しません。
Startup イベントと Exit イベント
Application には、アプリケーションのライフサイクルに関するイベントが用意されています。
特によく使うのは Startup と Exit です。
Startup は、アプリケーションが開始されたときに発生します。起動時の初期化処理、コマンドライン引数の解析、最初に表示するウィンドウの選択などに使えます。
app.Startup += (s, e) =>
{
foreach (string arg in e.Args)
{
Console.WriteLine(arg);
}
};
Exit は、アプリケーションが終了するときに発生します。ログの書き込み、設定の保存、一時ファイルの削除などに使えます。
app.Exit += (s, e) =>
{
// 終了時の後片付け
};
終了コードを設定したい場合は、Shutdown メソッドに値を渡します。
Application.Current.Shutdown(1);
この値は Exit イベントの ApplicationExitCode から取得できます。
Windows コレクションを列挙する
Application.Current.Windows を使うと、現在開いているウィンドウを列挙できます。
foreach (Window window in Application.Current.Windows)
{
Console.WriteLine($"{window.Title}: IsVisible={window.IsVisible}");
}
特定の型のウィンドウだけを探したい場合は、OfType<T> を使えます。
using System.Linq;
using System.Windows;
MainWindow mainWindow = Application.Current.Windows
.OfType<MainWindow>()
.FirstOrDefault();
すべてのサブウィンドウを閉じたい場合は、列挙中にコレクションが変更されないように、一度配列にコピーしてから閉じるのが安全です。
Window[] windows = Application.Current.Windows
.Cast<Window>()
.Where(w => w != Application.Current.MainWindow)
.ToArray();
foreach (Window window in windows)
{
window.Close();
}
Close() を呼び出すと、ウィンドウが閉じられ、Windows コレクションからも削除されます。そのため、コレクションを直接列挙しながら閉じると、列挙中にコレクションが変更される可能性があります。
ShutdownMode
Application を理解するうえで、ShutdownMode も重要です。
ShutdownMode は、どのタイミングでアプリケーションを終了するかを指定するプロパティです。
| 値 | 意味 |
|---|---|
OnLastWindowClose |
最後のウィンドウが閉じられたときに終了する |
OnMainWindowClose |
メインウィンドウが閉じられたときに終了する |
OnExplicitShutdown |
Shutdown() が呼ばれるまで終了しない |
既定値は OnLastWindowClose です。
たとえば、メインウィンドウが閉じられたらアプリケーション全体を終了したい場合は、次のように設定します。
app.ShutdownMode = ShutdownMode.OnMainWindowClose;
タスクトレイ常駐アプリのように、ウィンドウを閉じてもプロセスは終了させたくない場合は、OnExplicitShutdown を使うことがあります。
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
この場合は、終了したいタイミングで明示的に Shutdown() を呼び出します。
Application.Current.Shutdown();
App.xaml との関係
通常の WPF プロジェクトでは、Application クラスを直接 Main メソッドで作る代わりに、App.xaml と App.xaml.cs を使います。
App.xaml には、StartupUri やアプリケーション全体のリソースを記述できます。
<Application x:Class="SampleApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<SolidColorBrush x:Key="AccentBrush" Color="SteelBlue" />
</Application.Resources>
</Application>
App.xaml.cs 側では、Application を継承した App クラスを定義します。
using System.Windows;
namespace SampleApp;
public partial class App : Application
{
}
ビルド時には、WPF のビルド処理によってエントリポイントが生成されます。そのため、通常は自分で Main メソッドを書く必要はありません。
ただし、今回見たようにコードだけで Application を作ると、App.xaml が裏側で何をしているのかを理解しやすくなります。
まとめ
System.Windows.Application は、WPF アプリケーション全体を管理するクラスです。
Current で現在のアプリケーションにアクセスし、MainWindow で中心となるウィンドウを管理し、Properties で簡単な共有データを保持し、StartupUri で起動時に表示する画面を指定し、Windows で開いているウィンドウを列挙できます。
また、Startup や Exit イベントを使うことで、起動時の初期化処理や終了時の後片付けを記述できます。ShutdownMode を理解しておくと、複数ウィンドウのアプリケーションや常駐アプリでも、終了タイミングを意図通りに制御できます。
WPF の画面作成では Window や Control に目が行きがちですが、それらをアプリケーションとして動かしている中心には Application クラスがあります。