編譯 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 元件都存在於已安裝 .NET Framework 的每部電腦上相同的位置,因此不需要在資訊清單中包含所有 .NET Framework 參考元件的所有資訊。

標記編譯 - 第一階段

在此步驟中,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 的, 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 的 來卸載所有參考元件的優點。

標記編譯 - 第二階段

並非所有 XAML 頁面都會在標記編譯的傳遞 1 期間進行編譯。 目前,具有本機定義型別參考的 XAML 檔案(相同專案中其他位置程式碼中定義的類型參考)會豁免編譯。 這是因為這些本機定義的類型只存在於來源中,而且尚未經過編譯。 為了判斷此情況,剖析器會使用牽涉到在標記檔案中尋找 x:Name 等項目的啟發方式。 找到這類執行個體之後,就會將標記檔案的編譯延後到程式碼檔編譯完成,在那之後,第二階段的標記編譯才會處理這些檔案。

檔案分類

建置流程會根據作為目標位置的應用程式組件,將輸出檔案放在不同的資源群組中。 在一般未當地語系化的應用程式中,所有標記為 Resource 的資料檔案會放在主組件 (可執行檔或程式庫) 中。 在專案中設定時 UICulture ,所有已編譯的 XAML 檔案和特別標示為語言特定的資源都會放在附屬資源元件中。 此外,所有非語言相關的資源會放在主組件中。 在建置流程的這個步驟中,會做出判斷。

專案檔中的 ApplicationDefinitionPageResource 建置動作可以用 Localizable 中繼資料 (可接受的值為 truefalse) 增強,該中繼資料會指出檔案為特定語言或非語言相關。

核心編譯

核心編譯步驟牽涉到程式碼檔的編譯。 這是由特定語言之目標檔案 Microsoft.CSharp.targets 和 Microsoft.VisualBasic.targets 的邏輯進行協調。 如果啟發方式判斷標記編譯器的單一階段即已足夠,則會產生主組件。 不過,如果專案中的一或多個 XAML 檔案具有本機定義型別的參考,則會產生暫時的 .dll 檔案,以便在完成標記編譯的第二個階段之後建立最終的應用程式元件。

資訊清單產生

在建置程式結束時,所有應用程式元件和內容檔案都就緒之後,就會產生應用程式的 ClickOnce 資訊清單。

部署資訊清單檔會描述部署模型︰目前的版本、更新行為,以及發行者身分識別和數位簽章。 此資訊清單預期是由處理部署的系統管理員所撰寫。 副檔名為 .xbap (適用于 XAML 瀏覽器應用程式 (XBAP)和已安裝應用程式的 .application。 前者是由 HostInBrowser 專案屬性所指定,因此資訊清單會將應用程式識別為由瀏覽器裝載。

應用程式資訊清單 (.exe.manifest 檔案) 會描述應用程式組件和相依程式庫,並列出應用程式所需的權限。 此檔案預期是由應用程式開發人員所撰寫。 若要啟動 ClickOnce 應用程式,使用者會開啟應用程式的部署資訊清單檔案。

這些資訊清單檔案一律會針對 XBAP 建立。 若是已安裝的應用程式,除非將專案檔中的 GenerateManifests 屬性指定為 true 值,否則不會建立這些檔案。

XBAP 會透過以上取得指派給一般網際網路區域應用程式的兩個額外許可權: WebBrowserPermissionMediaPermission 。 WPF 建置系統會在應用程式資訊清單中宣告這些許可權。

累加建置支援

WPF 建置系統提供累加組建的支援。 該系統對於偵測標記或程式碼中所做的變更相當明確,而且只會編譯受變更影響的成品。 累加建置機制使用下列檔案:

  • $(組件名稱)_MarkupCompiler.Cache 檔案,用於維護目前的編譯器狀態。

  • $( AssemblyName )_MarkupCompiler.lref 檔案,以快取具有本機定義型別參考的 XAML 檔案。

以下是管理累加建置的一組規則:

  • 檔案是建置系統偵測變更的最小單位。 因此對於程式碼檔,建置系統無法得知是否變更類型或是否新增程式碼。 同樣的情況也適用於專案檔。

  • 累加建置機制必須能夠辨識 XAML 頁面定義類別或使用其他類別。

  • 如果 Reference 項目變更,則會重新編譯所有頁面。

  • 如果程式碼檔變更,則會重新編譯所有具有本機定義之類型參考的頁面。

  • 如果 XAML 檔案變更:

    • 如果 XAML 在專案中宣告為 Page :如果 XAML 沒有本機定義的類型參考,請重新編譯 XAML 加上具有本機參考的所有 XAML 頁面;如果 XAML 具有本機參考,請重新編譯具有本機參考的所有 XAML 頁面。

    • 如果 XAML 在專案中宣告為 ApplicationDefinition :重新編譯所有 XAML 頁面(原因:每個 XAML 都有可能已變更的類型參考 Application )。

  • 如果專案檔將程式碼檔宣告為應用程式定義,而不是 XAML 檔案:

    • 檢查專案檔中的 ApplicationClassName 值是否已變更 (是否有新的應用程式類型)。 如果是,請重新編譯整個應用程式。

    • 否則,請使用本機參考重新編譯所有 XAML 頁面。

  • 如果專案檔變更︰請套用所有前述規則,並查看哪些項目需要重新編譯。 對下列屬性的變更會觸發完整的重新編譯:AssemblyNameIntermediateOutputPathRootNamespaceHostInBrowser

以下是可能發生的重新編譯情節:

  • 重新編譯整個應用程式。

  • 只會重新編譯具有本機定義型別參考的 XAML 檔案。

  • 不重新編譯任何項目 (如果專案中沒有任何變更)。

另請參閱