今回はWPFにおけるアプリケーション管理についてです。

WPFではアプリケーションの開始から終了、実行中のアプリケーションを管理するクラスとしてSystem.Windows.Applicationクラスが用意されています。
まずはMSDNでアプリケーション管理としてApplicationクラスがどのように説明されているかを見てみましょう。

アプリケーションは、ユーザー インターフェイス (UI)、ビジネス ロジック、データ アクセス ロジック、コントロール、データなど、多様なアプリケーション固有の要素で構成されています。
これらの要素は、通常はアプリケーションごとに異なります。
ただし、アプリケーションの実装と管理で共通に使用される機能のセットを共有できることが多々あります。
WPF では、この共通のアプリケーションを対象とする機能が Application クラスでカプセル化されており、次のサービスを提供します。

・共通アプリケーション インフラストラクチャを作成し、管理する。
・アプリケーションの有効期間を追跡し、これと対話する。
・コマンド ライン パラメータを取得し、処理する。
・アプリケーション スコープのプロパティとリソースを共有する。
・未処理の例外を検出し、これに応答する。
・終了コードを返す。
・スタンドアロン アプリケーションのウィンドウを管理する。
・ナビゲーションを追跡し、管理する。

アプリケーションでこれらのサービスを使用するには、Application クラスを使用して、アプリケーション定義を実装する必要があります。

ApplicationクラスはVisual Studioで「WPFアプリケーションプロジェクト」を作成した場合、既定でマークアップファイルとランタイムコードの分離ファイルが作成されます。

VB
<Application x:Class="Application"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   StartupUri="Window1.xaml">
</Application>

Class Application
 
    ' Startup、Exit、DispatcherUnhandledException などのアプリケーション レベルのイベントは、
    ' このファイルで処理できます。
 
End Class

C#
<Application x:Class="WpfApplication1.App"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   StartupUri="Window1.xaml">
</Application>

namespace WpfApplication1
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
    }
}

アプリケーション起動時には、オペレーティングシステムが呼び出す初めのポイントをアプリケーションに含める必要があります。
MSDNでは下記のように説明されています。

スタンドアロン アプリケーションや XAML ブラウザ アプリケーション (XBAP) を実行できるようにするには、一定レベルのインフラストラクチャの実装が必要です。このインフラストラクチャの最も重要な部分はエントリ ポイントです。ユーザーがアプリケーションを起動するとき、オペレーティング システムはエントリ ポイントを呼び出します。これは、オペレーティング システムがアプリケーションを起動するための機能としてよく知られています。
従来、テクノロジに応じて、このコードの一部または全部を開発者が記述する必要がありました。しかし、WPF では、アプリケーション定義のマークアップ ファイルを MSBuild ApplicationDefinition 項目としてプロジェクトファイルに構成すると、コードが自動生成されます。

説明文での「MSBuild」の詳細についてはこちらを参考にして下さい。

一般的に「Main」メソッドがエントリポイントになり、アプリケーション起動時に呼ばれます。
ですがVisual Studioを用いて作成したWPFアプリケーションではこの「Main」メソッドが見当たりません。
WPFアプリケーションではApplication.xamlまたはApp.xamlファイルをプロジェクトに含めている場合、MSBuildが下記のコードを自動生成します。

VB
'''<summary>
'''Application
'''</summary>
Partial Public Class Application
    Inherits System.Windows.Application
 
    '''<summary>
    '''InitializeComponent
    '''</summary>
    <System.Diagnostics.DebuggerNonUserCodeAttribute()>  _
    Public Sub InitializeComponent()
 
        #ExternalSource("..\..\Application.xaml",4)
        Me.StartupUri = New System.Uri("Window1.xaml", System.UriKind.Relative)
 
        #End ExternalSource
    End Sub
 
    '''<summary>
    '''Application Entry Point.
    '''</summary>
    <System.STAThreadAttribute(),  _
    System.Diagnostics.DebuggerNonUserCodeAttribute()>  _
    Public Shared Sub Main()
        Dim app As Application = New Application
        app.InitializeComponent
        app.Run
    End Sub
End Class

C#
namespace WpfApplication1 { 
    /// <summary>
    /// App
    /// </summary>
    public partial class App : System.Windows.Application {
 
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public void InitializeComponent() {
 
            #line 4 "..\..\App.xaml"
            this.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);
 
            #line default
            #line hidden
        }
 
        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public static void Main() {
            WpfApplication1.App app = new WpfApplication1.App();
            app.InitializeComponent();
            app.Run();
        }
    }
}

上記自動生成されたコードは、プロジェクトファイルと同ディレクトリに作成される下記のディレクトリに作成されます。

Debug時
\obj\Debug\TempPE\Application.g.vb (VB)
\obj\Degub\TempPE\App.g.cs (C#)

Release時
\obj\Release\Application.g.vb (VB)
\obj\Release\App.g.vb (C#)

通常であれば独自でエントリポイントを作成して、アプリケーション起動をカスタマイズする必要はありませんが、アプリケーションの初期化が行われるまえに特定の処理を行いたい場合などに、独自のエントリポイントを作成する事も出来ます。
手順としては下記の通りです。
  1. 既存のApplication.xaml又は、App.xamlをプロジェクトから削除する。
  2. エントリポイントを定義する為のクラスをプロジェクトに追加する。
  3. 静的メソッドとしてMainメソッドを定義し、STAThreadAttributeを属性として定義する。
  4. プロジェクトのスタートアップを作成したクラスを指定する。
ではコード例を見てみましょう。

VB
Public Class Program
 
    <STAThread()> _
    Public Shared Sub Main(ByVal args() As String)
        Dim app As New Application()
        Dim w As New Window1()
        app.Run(w)
    End Sub
 
End Class

C#
namespace WpfApplication4
{
    public class Program
    {
        [STAThread()]
        public static void Main(string[] args)
        {
            Application app = new Application();
            Window1 w = new Window1();
            app.Run(w);
        }
    }
}

WPFではSTAスレッドである事が必須とされています。既定ではSTAスレッドとして動作しますが、エントリポイント作成する際には明示的にSTAThread属性を定義する方がいいでしょう。

次にアプリケーションの有効期間についての制御です。
Applicationクラスではアプリケーションの初期化後や終了時などをイベントによって受け取り、独自の処理を構成する事が出来ます。

まずはアプリケーションの初期化後に発生するイベントのStartupイベントです。
Startupイベントは一般的にはアプリケーションのメインウィンドウを起動する為に使用されます。コード例を見てみましょう。

VB
Class Application
 
    Private Sub Application_Startup(ByVal sender As Object, ByVal e As System.Windows.StartupEventArgs) Handles Me.Startup
        Me.MainWindow = New Window1()
        Me.MainWindow.Show()
 
        '一番初めにインスタンス化されたウィンドウはメインウィンドウとなる為、上記と同様に使用する事が出来る。
        'Dim w As New Window1()
        'w.Show()
    End Sub
 
End Class

C#
namespace WpfApplication1
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.MainWindow = new Window1();
            this.MainWindow.Show();
 
            //一番初めにインスタンス化されたウィンドウはメインウィンドウとなる為、上記と同様に使用する事が出来る。
            //Window1 w = new Window1();
            //w.Show();
        }
    }
}

Startupイベントを使用しメインウィンドウを起動したり、メインウィンドウ起動前に独自の処理を構成する事が出来ます。

次はアプリケーション終了時に発生するExitイベントについてです。
Exitイベントは一般的にアプリケーションの状態保存や最終処理が必要な場合に使用します。コード例を見てみましょう。

VB
Class Application
 
    Private Sub Application_Exit(ByVal sender As System.Object, ByVal e As System.Windows.ExitEventArgs)
        'アプリケーションの状態保存や最終処理を行う。
    End Sub
 
End Class

C#
namespace WpfApplication1
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
        private void Application_Exit(object sender, ExitEventArgs e)
        {
            //アプリケーションの状態保存や最終処理を行う。
        }
    }
}

このようにExitイベントを使用して独自の最終処理を構成する事が出来ます。

では最後に、アプリケーション起動中に予期せぬエラーなどが発生し、エラーが処理されずに未処理のエラーが存在すると、既定ではOSよりエラーダイアログが表示されますが、一般的にはこのようなダイアログは表示されないように構成する必要があります。
未処理のエラーをApplicationクラスでは未処理のエラーを補足する為に使用するDispatcherUnhandledExceptionがあります。
DispatcherUnhandledExceptionイベントは一般的に開発者向けのイベントログを出力したり、ユーザーに解り易いメッセージを表示するなどに使用します。コード例を見てみましょう。

VB
Class Application
 
    Private Sub Application_DispatcherUnhandledException(ByVal sender As Object, ByVal e As System.Windows.Threading.DispatcherUnhandledExceptionEventArgs) Handles Me.DispatcherUnhandledException
        '開発者向けのイベントログや、ユーザーに解り易いエラーメッセージを表示したりする。
    End Sub
 
End Class

C#
namespace WpfApplication1
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
 
        private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            //開発者向けのイベントログや、ユーザーに解り易いエラーメッセージを表示したりする。
        }
    }
}

DispatcherUnhandledExceptionイベントを使用して、アプリケーションの異常終了時などのフォローを行うようにしましょう。

今回はアプリケーション管理としてApplicationクラスの入門的一部を取り上げました。
Applicationクラスには様々なイベントなどがあり、アプリケーション管理について色々制御が行えますので今回取り上げた以外にも色々使用し、アプリケーション管理について学習されてみては如何でしょうか。

to be continue・・・

コメントの入力
タイトル
名前
Url
コメント