WPF 應用程式資源、內容和資料檔案
Microsoft Windows 應用程式通常取決於包含不可執行資料的檔案,例如 Extensible Application Markup Language (XAML)、影像、視訊和音訊。 Windows Presentation Foundation (WPF) 提供設定、識別及使用這些資料檔案類型 (稱為應用程式資料檔案) 的特殊支援。 這項支援是以一組特定的應用程式資料檔案類型為中心,包括:
資源檔案︰編譯為可執行檔或程式庫 WPF 組件的資料檔案。
內容檔案︰與可執行 WPF 組件具有明確關聯的獨立資料檔案。
原點網站檔案︰與可執行 WPF 組件沒有任何關聯的獨立資料檔案。
這三種檔案類型之間的其中一個重要區別是資源檔和內容檔是建置階段的已知檔案;組件並明確知道這兩種檔案。 不過,組件可能完全不知道原點網站檔案,或僅透過 Pack 統一資源識別項 (URI) 參考以隱含方式得知這種檔案;若為後者的情況,則無法保證所參考的原點網站檔案確實存在。
若要參考應用程式資料檔案,Windows Presentation Foundation (WPF) 會使用 Pack 統一資源識別項 (URI) 配置,如 WPF 中的 Pack URI 中所述。
本主題描述何設定及使用應用程式資料檔案。
資源檔
若應用程式資料檔案必須一律可供應用程式使用,確保可用性的唯一方法是將檔案編譯成應用程式的主要可執行檔組件或是應用程式的其中一個參考組件。 這種類型的應用程式資料檔案稱為「資源檔」。
應該使用資源檔的時機包括:
您不需要在資源檔編譯成組件之後更新該檔案的內容。
您想要透過減少檔案相依性數目的方式,簡化複雜的應用程式發佈程序。
您的應用程式資料檔案必須可以當地語系化 (請參閱 WPF 全球化和當地語系化概觀)。
注意
本節中所述的資源檔案不同於 XAML 資源中所述的資源檔案,也不同於管理應用程式資源 (.NET) 中所述的內嵌資源或連結資源。
設定資源檔
在 WPF 中,資源檔案是包括在 Microsoft 建置引擎 (MSBuild) 專案中作為 Resource
項目的檔案。
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>
注意
在 Visual Studio 中,建立資源檔案的方式是將檔案新增至專案,並將其 Build Action
設定為 Resource
。
建置專案時,MSBuild 會將資源編譯為組件。
使用資源檔
若要載入資源檔案,您可以呼叫 Application 類別的 GetResourceStream 方法,並傳遞可識別必要資源檔案的 Pack URI。 GetResourceStream 會傳回 StreamResourceInfo 物件,而此物件會將資源檔案公開為 Stream,並描述其內容類型。
例如,下列程式碼顯示如何使用 GetResourceStream 來載入 Page 資源檔案,並將其設定為 Frame (pageFrame
) 的內容:
// Navigate to xaml page
Uri uri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetResourceStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;
' Navigate to xaml page
Dim uri As New Uri("/PageResourceFile.xaml", UriKind.Relative)
Dim info As StreamResourceInfo = Application.GetResourceStream(uri)
Dim reader As New System.Windows.Markup.XamlReader()
Dim page As Page = CType(reader.LoadAsync(info.Stream), Page)
Me.pageFrame.Content = page
呼叫 GetResourceStream 可讓您存取 Stream 時,您需要執行額外工作,以將其轉換為您用來進行設定的屬性類型。 您可以改為使用程式碼,以將資源檔案直接載入至類型的屬性,讓 WPF 處理 Stream 的開啟和轉換。
下列範例顯示如何使用程式碼,以將 Page 直接載入至 Frame (pageFrame
)。
Uri pageUri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
Dim pageUri As New Uri("/PageResourceFile.xaml", UriKind.Relative)
Me.pageFrame.Source = pageUri
下列範例相當於前一個範例的標記對等用法。
<Frame Name="pageFrame" Source="PageResourceFile.xaml" />
應用程式程式碼檔案作為資源檔
您可以使用 Pack URI 參考一組特殊的 WPF 應用程式程式碼檔案,包括視窗、頁面、非固定格式文件和資源字典。 例如,您可以使用 Pack URI 來設定 Application.StartupUri 屬性,而 Pack URI 參考您想要在啟動應用程式時載入的視窗或頁面。
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="SOOPage.xaml" />
XAML 檔案以 Page
項目形式包括在 MSBuild 專案中時,您可以執行此動作。
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
注意
在 Visual Studio 中,您會將新的 Window、NavigationWindow、Page、FlowDocument 或 ResourceDictionary 新增至專案,而且標記檔案的 Build Action
將會預設為 Page
。
編譯具有 Page
項目的專案時,XAML 項目會轉換為二進位格式並編譯成相關聯的組件。 因此,這些檔案可以比照一般資源檔的方式來使用。
注意
如果 XAML 檔案設定為 Resource
項目,而且沒有程式碼後置檔案,則原始 XAML 會編譯為組件,而非原始 XAML 的二進位版本。
內容檔
「內容檔」是以鬆散檔案的形式連同可執行檔組件一併發佈。 雖然這種檔案並未編譯成組件,但是編譯組件時使用的中繼資料會建立與每個內容檔的關聯。
如果應用程式需要一組特定的應用程式資料檔案,而您不想在更新這些檔案時重新編譯使用它們的組件,您應該使用內容檔。
設定內容檔
若要將內容檔案新增至專案,必須以 Content
項目形式包括應用程式資料檔案。 此外,因為內容檔案未直接編譯為組件,所以您需要設定 MSBuild CopyToOutputDirectory
中繼資料元素,以指定將內容檔案複製至所建置組件的相對位置。 如果您想在每次建置專案時將資源複製至建置輸出資料夾,則請使用 Always
值來設定 CopyToOutputDirectory
中繼資料元素。 否則,您可以使用 PreserveNewest
值,確保只會將最新版本的資源複製至建置輸出資料夾。
以下顯示設定為內容檔的檔案;只有在將新版本的資源新增至專案時,這個內容檔才會複製到建置輸出資料夾。
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Content Include="ContentFile.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...
</Project>
注意
在 Visual Studio 中,建立內容檔案的方式是將檔案新增至專案,並將其 Build Action
設定為 Content
,以及將其 Copy to Output Directory
設定為 Copy always
(與 Always
相同) 和 Copy if newer
(與 PreserveNewest
相同)。
建置專案時,會將 AssemblyAssociatedContentFileAttribute 屬性編譯為每個內容檔案的組件中繼資料。
[assembly: AssemblyAssociatedContentFile("ContentFile.xaml")]
AssemblyAssociatedContentFileAttribute 的值表示內容檔案的路徑相對於其在專案中的位置。 例如,如果內容檔案之前位於專案子資料夾中,則會將其他路徑資訊併入至 AssemblyAssociatedContentFileAttribute 值。
[assembly: AssemblyAssociatedContentFile("Resources/ContentFile.xaml")]
AssemblyAssociatedContentFileAttribute 值也是建置輸出資料夾中內容檔案路徑的值。
使用內容檔
若要載入內容檔案,您可以呼叫 Application 類別的 GetContentStream 方法,並傳遞可識別所需內容檔案的 Pack URI。 GetContentStream 會傳回 StreamResourceInfo 物件,而此物件會將內容檔案公開為 Stream,並描述其內容類型。
例如,下列程式碼顯示如何使用 GetContentStream 來載入 Page 內容檔案,並將其設定為 Frame (pageFrame
) 的內容。
// Navigate to xaml page
Uri uri = new Uri("/PageContentFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetContentStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;
' Navigate to xaml page
Dim uri As New Uri("/PageContentFile.xaml", UriKind.Relative)
Dim info As StreamResourceInfo = Application.GetContentStream(uri)
Dim reader As New System.Windows.Markup.XamlReader()
Dim page As Page = CType(reader.LoadAsync(info.Stream), Page)
Me.pageFrame.Content = page
呼叫 GetContentStream 可讓您存取 Stream 時,您需要執行額外工作,以將其轉換為您用來進行設定的屬性類型。 您可以改為使用程式碼,以將資源檔案直接載入至類型的屬性,讓 WPF 處理 Stream 的開啟和轉換。
下列範例顯示如何使用程式碼,以將 Page 直接載入至 Frame (pageFrame
)。
Uri pageUri = new Uri("/PageContentFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
Dim pageUri As New Uri("/PageContentFile.xaml", UriKind.Relative)
Me.pageFrame.Source = pageUri
下列範例相當於前一個範例的標記對等用法。
<Frame Name="pageFrame" Source="PageContentFile.xaml" />
來源網站檔
資源檔案與組件具有明確關聯性,而這些組件會與其一起散發,如 AssemblyAssociatedContentFileAttribute 所定義。 但是在某些情況下,您可能想在組件和應用程式資料檔案之間建立隱含或不存在的關聯性,這些情況包括:
檔案在編譯時期並不存在。
在執行階段之前,您不知道組件需要哪些檔案。
您不想在更新檔案時重新編譯其關聯的組件。
應用程式使用大型的資料檔案,例如音訊和視訊,而您只想讓使用者自行選擇是否下載這些檔案。
您可以使用傳統 URI 配置 (例如 file:///
和 http://
配置) 來載入這些類型的檔案。
<Image Source="file:///C:/DataFile.bmp" />
<Image Source="http://www.datafilewebsite.com/DataFile.bmp" />
不過,file:///
和 http://
配置需要您的應用程式受到完全信任。 如果您的應用程式是從網際網路或內部網路啟動的 XAML 瀏覽器應用程式 (XBAP),並且只要求從這些位置所啟動應用程式所允許的使用權限集合,則只能從應用程式的原點網站 (啟動位置) 載入鬆散檔案。 這類檔案稱為「來源網站」檔。
來源網站檔是部分信任應用程式的唯一選擇,但並不是只適用於部分信任應用程式。 完全信任應用程式可能還是需要載入它們在建置階段並不知道的應用程式資料檔案;雖然完全信任應用程式可以使用 file:///,但是應用程式資料檔案可能會安裝在應用程式組件的相同資料夾或子資料夾中。 在此情況下,使用來源網站參考比使用 file:/// 簡單,因為使用 file:/// 時,您必須找出檔案的完整路徑。
注意
在用戶端機器上,不會使用 XAML 瀏覽器應用程式 (XBAP) 來快取原點網站檔案,但會快取內容檔案。 因此,只有在特別要求時,才會下載來源網站檔。 如果 XAML 瀏覽器應用程式 (XBAP) 應用程式具有大型的媒體檔案,則將這些檔案設定為原點網站檔案即表示初始應用程式的啟動速度將會變快,而且只會視需要下載這些檔案。
設定來源網站檔
如果原點網站檔案在編譯時期不存在或未知,則您需要使用傳統部署機制,以確保能夠在執行階段取得必要檔案,包括使用 XCopy
命令列程式或 Microsoft Windows Installer。
如果您確實知道編譯時期要放在原點網站的檔案,但還是想要避免產生明確相依性,則可以將這些檔案新增至 MSBuild 專案,作為 None
項目。 與內容檔案一樣,您需要設定 MSBuild CopyToOutputDirectory
屬性,以指定 Always
值或 PreserveNewest
值,來指定將原點網站檔案複製至所建置組件的相對位置。
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
注意
在 Visual Studio 中,將檔案新增至專案,並將其 Build Action
設定為 None
,來建立原點網站檔案。
建置專案時,MSBuild 會將指定的檔案複製至建置輸出資料夾。
使用來源網站檔
若要載入原點網站檔案,您可以呼叫 Application 類別的 GetRemoteStream 方法,並傳遞可識別所需原點網站檔案的 Pack URI。 GetRemoteStream 會傳回 StreamResourceInfo 物件,而此物件會將原點網站檔案公開為 Stream,並描述其內容類型。
例如,下列程式碼顯示如何使用 GetRemoteStream 來載入 Page 原點網站檔案,並將其設定為 Frame (pageFrame
) 的內容。
// Navigate to xaml page
Uri uri = new Uri("/SiteOfOriginFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetRemoteStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;
' Navigate to xaml page
Dim uri As New Uri("/SiteOfOriginFile.xaml", UriKind.Relative)
Dim info As StreamResourceInfo = Application.GetRemoteStream(uri)
Dim reader As New System.Windows.Markup.XamlReader()
Dim page As Page = CType(reader.LoadAsync(info.Stream), Page)
Me.pageFrame.Content = page
呼叫 GetRemoteStream 可讓您存取 Stream 時,您需要執行額外工作,以將其轉換為您用來進行設定的屬性類型。 您可以改為使用程式碼,以將資源檔案直接載入至類型的屬性,讓 WPF 處理 Stream 的開啟和轉換。
下列範例顯示如何使用程式碼,以將 Page 直接載入至 Frame (pageFrame
)。
Uri pageUri = new Uri("pack://siteoforigin:,,,/SiteOfOriginFile.xaml", UriKind.Absolute);
this.pageFrame.Source = pageUri;
Dim pageUri As New Uri("pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml", UriKind.Absolute)
Me.pageFrame.Source = pageUri
下列範例相當於前一個範例的標記對等用法。
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
在變更組建類型之後重建
在變更應用程式資料檔案的組建類型之後,您必須重建整個應用程式,以確認套用這些變更。 若您只建置應用程式,則不會套用變更。