WPF アプリケーションをコンパイルする

Windows Presentation Foundation (WPF) アプリケーションは、.NET Framework の実行可能ファイル (.exe)、 ライブラリ (.dll)、または両方のタイプのアセンブリの組み合わせとしてビルドできます。 このトピックでは、WPF アプリケーションをビルドする方法を紹介し、ビルド プロセスの主な手順について説明します。

WPF アプリケーションのビルド

WPF アプリケーションは、次の方法でコンパイルできます。

WPF ビルド パイプライン

WPF プロジェクトがビルドされるときには、言語固有のターゲットと WPF 固有のターゲットの組み合わせが呼び出されます。 これらのターゲットを実行するプロセスはビルド パイプラインと呼ばれます。主要な手順を次の図に示します。

WPF build process

ビルド前の初期化

ビルドの前に、MSBuild では、次のような重要なツールとライブラリの場所が確認されます。

  • .NET Framework。

  • Windows SDK ディレクトリ。

  • WPF 参照アセンブリの場所。

  • アセンブリ検索パスのプロパティ。

MSBuild でアセンブリが最初に検索される場所は、参照アセンブリ ディレクトリ (%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.0\) です。 この手順では、ビルド プロセスはさまざまなプロパティと項目グループを初期化し、必要なクリーンアップ作業も実行します。

参照の解決

ビルド プロセスは、アプリケーション プロジェクトのビルドに必要なアセンブリを探して、バインドします。 このロジックは、ResolveAssemblyReference タスクに含まれます。 プロジェクト ファイル内で Reference として宣言されたすべてのアセンブリは、検索パスに関する情報と、すでにシステムにインストールされているアセンブリのメタデータと共にタスクに渡されます。 タスクでは、アセンブリが検索され、インストールされているアセンブリのメタデータを使用して、出力マニフェストに含める必要のないコアの WPF アセンブリを除外するフィルター処理が行われます。 これは、ClickOnce マニフェストに冗長な情報が含まれるのを避けるために行われます。 たとえば、PresentationFramework.dll は、WPF で WPF 用にビルドされる代表的なアプリケーションとみなすことができ、すべての WPF アセンブリは、.NET Framework がインストールされているすべてのコンピューター上の同じ場所に存在するため、マニフェストにすべての .NET Framework 参照アセンブリに関するすべての情報を含める必要はありません。

マークアップ コンパイル - パス 1

この手順では、XAML ファイルを解析してコンパイルし、ランタイムで XML の解析やプロパティ値の検証に時間を費やさずに済むようにします。 コンパイルされた XAML ファイルは事前にトークン化されるため、実行時の読み込み時間は、XAML ファイルを読み込む場合よりもはるかに短縮されます。

この手順では、Page ビルド項目である XAML ファイルごとに、次のアクティビティが実行されます。

  1. XAML ファイルがマークアップ コンパイラによって解析されます。

  2. その XAML のコンパイル済みの表現が作成され、obj\Release フォルダーにコピーされます。

  3. 新しい部分クラスの CodeDOM 表現が作成され、obj\Release フォルダーにコピーされます。

さらに、XAML ファイルごとに、言語固有のコード ファイルが生成されます。 たとえば、Visual Basic プロジェクトの Page1.xaml ページについては Page1.g.vb が生成されます。C# プロジェクトの Page1.xaml ページについては Page1.g.cs が生成されます。 ファイル名の ".g" は、ファイルが生成されたコードであり、マークアップ ファイルのトップレベルの要素 (PageWindow など) に対する部分クラス宣言を持つことを示しています。 クラスは C# の partial 修飾子 (Visual Basic では Extends) によって宣言され、他の場所 (通常は分離コード ファイル Page1.xaml.cs) に別のクラス宣言があることを示します。

部分クラスは、適切な基本クラス (ページの Page など) から拡張され、System.Windows.Markup.IComponentConnector インターフェイスを実装します。 IComponentConnectorインターフェイスには、コンポーネントを初期化し、コンテンツ内の要素の名前とイベントを結びつけるメソッドがあります。 その結果、生成されたコード ファイルには、次のようなメソッドの実装が含まれます。

public void InitializeComponent() {
    if (_contentLoaded) {
        return;
    }
    _contentLoaded = true;
    System.Uri resourceLocater =
        new System.Uri(
            "window1.xaml",
            System.UriKind.RelativeOrAbsolute);
    System.Windows.Application.LoadComponent(this, resourceLocater);
}
Public Sub InitializeComponent() _

    If _contentLoaded Then
        Return
    End If

    _contentLoaded = True
    Dim resourceLocater As System.Uri = _
        New System.Uri("mainwindow.xaml", System.UriKind.Relative)

    System.Windows.Application.LoadComponent(Me, resourceLocater)

End Sub

既定では、マークアップ コンパイルは、MSBuild エンジンと同じ AppDomain で実行されます。 これにより、パフォーマンスが大幅に向上します。 この動作は、AlwaysCompileMarkupFilesInSeparateDomain プロパティで切り替えることができます。 これには、個別の AppDomain をアンロードすることにより、すべての参照アセンブリをアンロードするという利点があります。

マークアップ コンパイル - パス 2

マークアップ コンパイルのパス 1 ですべての XAML ページがコンパイルされるわけではありません。 ローカルで定義された型参照 (同じプロジェクト内の他のコードで定義された型の参照) を含む XAML ファイルは、この時点ではコンパイルから除外されます。 これは、ローカルで定義された型は、ソース内にのみ存在し、まだコンパイルされていないためです。 これを判別するために、パーサーは、マークアップ ファイル内で x:Name などの項目を検索するヒューリスティックを使用します。 このようなインスタンスが見つかると、そのマークアップ ファイルのコンパイルは、コード ファイルがコンパイルされるまで延期され、その後、2 階目のマークアップ コンパイル パスで、これらのファイルが処理されます。

ファイルの分類

ビルド プロセスは、配置されるアプリケーション アセンブリに基づいて、出力ファイルを異なるリソース グループに分けます。 一般的なローカライズされないアプリケーションでは、Resource としてマークされたすべてのデータ ファイルは、メイン アセンブリ (実行可能ファイルまたはライブラリ) に配置されます。 プロジェクトで UICulture が設定されると、コンパイル済みのすべての XAML ファイルと、言語固有として明示的にマークされたリソースは、サテライト リソース アセンブリに配置されます。 さらに、言語に依存しないすべてのリソースは、メイン アセンブリに配置されます。 ビルド プロセスのこの手順で、この決定が行われます。

プロジェクト ファイル内の ApplicationDefinitionPage、および Resource ビルト アクションは、Localizable メタデータで拡張でき (受け入れられる値は truefalse)、これによって、ファイルが言語固有か、言語に依存しないかを指定します。

コア コンパイル

コア コンパイル手順では、コード ファイルのコンパイルが行われます。 これは Microsoft.CSharp.targets や Microsoft.VisualBasic.targets など、言語固有のターゲット ファイル内のロジックによって調整されます。 ヒューリスティックによってマークアップ コンパイラの 1 回のパスでは不十分であると判断されると、メイン アセンブリが生成されます。 ただし、プロジェクト内の 1 つ以上の XAML ファイルにローカルで定義された型の参照が含まれている場合、一時的な .dll ファイルが生成され、これによってマークアップ コンパイルの 2 回目のパスが完了すると、最終的なアプリケーション アセンブリが作成されます。

マニフェストの生成

ビルド プロセスの終わりに、すべてのアプリケーション アセンブリとコンテンツ ファイルの準備が整った後で、アプリケーションの ClickOnce マニフェストが生成されます。

配置マニフェスト ファイルは、配置モデル (現在のバージョン、更新動作、およびパブリッシャーの ID とデジタル署名) を記述します。 このマニフェストは、配置を処理する管理者が作成します。 ファイル拡張子は、.xbap (XAML ブラウザー アプリケーション (XBAP) 用) と、インストール型アプリケーションを表す .application です。 前者は HostInBrowser プロジェクト プロパティによって指定されるため、マニフェストはアプリケーションがブラウザーによってホストされることを識別します。

アプリケーション マニフェスト (.exe.manifest ファイル) は、アプリケーション アセンブリと依存ライブラリを記述し、アプリケーションに必要なアクセス許可をリストします。 このファイルは、アプリケーション開発者が作成します。 ClickOnce アプリケーションを起動するために、ユーザーはアプリケーションの配置マニフェスト ファイルを開きます。

これらのマニフェスト ファイルは、常に XBAP 用に作成されます。 インストール型アプリケーションの場合、プロジェクト ファイル内で GenerateManifests プロパティの値が true に指定されない限り、作成されません。

XBAP は、一般的なインターネット ゾーンのアプリケーションに割り当てられるアクセス許可に加えて、さらに 2 つのアクセス許可を取得します。つまり、WebBrowserPermissionMediaPermission です。 WPF ビルド システムでは、これらのアクセス許可がアプリケーション マニフェストで宣言されます。

インクリメンタル ビルドのサポート

WPF ビルド システムでは、インクリメンタル ビルドがサポートされています。 これは、マークアップやコードに加えられた変更を検出し、変更の影響を受けるアイテムだけをコンパイルするという高度な機能です。 インクリメンタル ビルド メカニズムは、次のファイルを使用します。

  • $(AssemblyName)_MarkupCompiler.Cache ファイル。コンパイラの現在の状態を保持します。

  • $(AssemblyName)_MarkupCompiler.lref ファイル。ローカルで定義された型への参照を含む XAML ファイルをキャッシュします。

インクリメンタル ビルドを制御する規則のセットを次に示します。

  • ビルド システムが変更を検出する最小単位は、ファイルです。 そのため、コード ファイルの場合、ビルド システムは、型が変更されたかどうか、またはコードが追加されたかどうかを検出できません。 プロジェクト ファイルの場合も同様です。

  • インクリメンタル ビルドのメカニズムでは、XAML ページでクラスを定義するのか、他のクラスを使用するのかを認識する必要があります。

  • Reference エントリが変更された場合は、すべてのページを再コンパイルします。

  • コード ファイルが変更された場合は、ローカルで定義された型の参照を含むすべてのページを再コンパイルします。

  • XAML ファイルが変更された場合:

    • XAML がプロジェクトで Page として宣言されている場合: XAML にローカルで定義された型参照が含まれていない場合は、その XAML と、ローカル参照が含まれているすべてのページを再コンパイルします。XAML にローカル参照が含まれている場合は、ローカル参照が含まれているすべての XAML ページを再コンパイルします。

    • XAML がプロジェクトで ApplicationDefinition として宣言されている場合: すべての XAML ページを再コンパイルします (理由: 各 XAML には、変更された可能性のある Application 型への参照が含まれています)。

  • プロジェクト ファイルで、コード ファイルが XAML ファイルではなくアプリケーション定義として宣言されている場合:

    • プロジェクト ファイル内の ApplicationClassName 値が変更されたかどうか (新しいアプリケーションの種類があるかどうか) を確認します。 変更されていた場合は、アプリケーション全体を再コンパイルします。

    • 変更されていなかった場合は、ローカル参照を含むすべての XAML ページを再コンパイルします。

  • プロジェクト ファイルが変更された場合、上記のすべての規則を適用し、再コンパイルする必要があるものを確認します。 AssemblyNameIntermediateOutputPathRootNamespace、および HostInBrowser プロパティが変更された場合は、再コンパイルが必要です。

次のような再コンパイルのシナリオが考えられます。

  • アプリケーション全体が再コンパイルされる。

  • ローカルで定義された型参照を含む XAML ファイルのみが再コンパイルされる。

  • 何も再コンパイルされない (プロジェクトに何も変更が加えられていない場合)。

関連項目