WPF 应用程序资源、内容和数据文件WPF Application Resource, Content, and Data Files

Microsoft Windows 应用程序通常依赖于包含不可执行的数据的文件,例如 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML)、图像、视频和音频。Microsoft Windows applications often depend on files that contain non-executable data, such as 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML), images, video, and audio. Windows Presentation Foundation (WPF)为配置、标识和使用这些类型的数据文件(称为应用程序数据文件)提供特殊支持。Windows Presentation Foundation (WPF) offers special support for configuring, identifying, and using these types of data files, which are called application data files. 这种支持主要针对一组特定的应用程序数据文件类型,包括:This support revolves around a specific set of application data file types, including:

  • 资源文件:编译为可执行文件或库 WPF 程序集的数据文件。Resource Files: Data files that are compiled into either an executable or library WPF assembly.

  • 内容文件:独立的数据文件,与可执行的 WPF 程序集具有显式关联。Content Files: Standalone data files that have an explicit association with an executable WPF assembly.

  • 源站点文件:与可执行 WPF 程序集没有关联的独立数据文件。Site of Origin Files: Standalone data files that have no association with an executable WPF assembly.

这三种类型的文件之间的一个重要区别是:资源文件和内容文件在生成时即为程序集所知;程序集明确知道它们的存在。One important distinction to make between these three types of files is that resource files and content files are known at build time; an assembly has explicit knowledge of them. 但对于源站点文件,程序集可能根本不知道它们,或者通过包统一资源标识符(URI)引用隐式了解;对于后一种情况,不能保证引用的源站点文件确实存在。For site of origin files, however, an assembly may have no knowledge of them at all, or implicit knowledge through a pack uniform resource identifier (URI) reference; the case of the latter, there is no guarantee that the referenced site of origin file actually exists.

若要引用应用程序数据文件,Windows Presentation Foundation (WPF)使用包统一资源标识符(URI)方案,详见 WPF 中的Pack uriTo reference application data files, Windows Presentation Foundation (WPF) uses the Pack uniform resource identifier (URI) Scheme, which is described in detail in Pack URIs in WPF).

本主题介绍如何配置和使用应用程序数据文件。This topic describes how to configure and use application data files.

资源文件Resource Files

如果应用程序数据文件必须始终可供某个应用程序使用,那么保证可用性的唯一方法是将其编译到应用程序的主可执行程序集内,或者它所引用的程序集内。If an application data file must always be available to an application, the only way to guarantee availability is to compile it into an application's main executable assembly or one of its referenced assemblies. 这种类型的应用程序数据文件称为资源文件This type of application data file is known as a resource file.

应在以下情况下使用资源文件:You should use resource files when:

  • 将资源文件编译到程序集内之后,无需更新资源文件的内容。You don't need to update the resource file's content after it is compiled into an assembly.

  • 希望通过减少文件依赖项的数量来简化应用程序分发的复杂性。You want to simplify application distribution complexity by reducing the number of file dependencies.

  • 应用程序数据文件需要可本地化(请参阅WPF 全球化和本地化概述)。Your application data file needs to be localizable (see WPF Globalization and Localization Overview).

备注

本节中所述的资源文件不同于XAML 资源中所述的资源文件,与管理应用程序资源(.net)中所述的嵌入或链接的资源不同。The resource files described in this section are different than the resource files described in XAML Resources and different than the embedded or linked resources described in Manage Application Resources (.NET).

配置资源文件Configuring Resource Files

在 WPF 中,资源文件是作为 Resource 项包含在 Microsoft 生成引擎(MSBuild)项目中的文件。In WPF, a resource file is a file that is included in an Microsoft build engine (MSBuild) project as a Resource item.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >  
  ...  
  <ItemGroup>  
    <Resource Include="ResourceFile.xaml" />  
  </ItemGroup>  
  ...  
</Project>  

备注

在 Visual Studio 中,可以通过将文件添加到项目并将其 Build Action 设置为 Resource来创建资源文件。In Visual Studio, you create a resource file by adding a file to a project and setting its Build Action to Resource.

生成项目时,MSBuild 会将资源编译到程序集中。When the project is built, MSBuild compiles the resource into the assembly.

使用资源文件Using Resource Files

若要加载资源文件,可以调用 Application 类的 GetResourceStream 方法,同时传递标识所需资源文件的包 URI。To load a resource file, you can call the GetResourceStream method of the Application class, passing a pack URI that identifies the desired resource file. GetResourceStream 返回一个 StreamResourceInfo 对象,该对象将资源文件公开为 Stream 并描述其内容类型。GetResourceStream returns a StreamResourceInfo object, which exposes the resource file as a Stream and describes its content type.

例如,下面的代码演示如何使用 GetResourceStream 加载 Page 资源文件并将其设置为 FramepageFrame)的内容:As an example, the following code shows how to use GetResourceStream to load a Page resource file and set it as the content of a 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时,需要执行其他工作,将其转换为你要将其设置到的属性的类型。While calling GetResourceStream gives you access to the Stream, you need to perform the additional work of converting it to the type of the property that you'll be setting it with. 相反,你可以让 WPF 通过使用代码将资源文件直接加载到类型的属性中来处理 Stream 的打开和转换。Instead, you can let WPF take care of opening and converting the Stream by loading a resource file directly into the property of a type using code.

下面的示例演示如何使用代码将 Page 直接加载到 FramepageFrame)。The following example shows how to load a Page directly into a Frame (pageFrame) using code.

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

下面的示例是与上例等效的标记。The following example is the markup equivalent of the preceding example.

<Frame Name="pageFrame" Source="PageResourceFile.xaml" />

作为资源文件的应用程序代码文件Application Code Files as Resource Files

使用包 Uri 可以引用一组特殊的 WPF 应用程序代码文件,包括 windows、页面、流文档和资源字典。A special set of WPF application code files can be referenced using pack URIs, including windows, pages, flow documents, and resource dictionaries. 例如,你可以使用一个包 URI 设置 Application.StartupUri 属性,该 URL 引用在应用程序启动时要加载的窗口或页面。For example, you can set the Application.StartupUri property with a pack URI that references the window or page that you would like to load when an application starts.

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    StartupUri="SOOPage.xaml" />

当将 XAML 文件作为 Page 项包含在 MSBuild 项目中时,可以执行此操作。You can do this when a XAML file is included in an MSBuild project as a Page item.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >  
  ...  
  <ItemGroup>  
    <Page Include="MainWindow.xaml" />  
  </ItemGroup>  
  ...  
</Project>  

备注

在 Visual Studio 中,向项目添加新的 WindowNavigationWindowPageFlowDocumentResourceDictionary 时,标记文件的 Build Action 默认为 PageIn Visual Studio, you add a new Window, NavigationWindow, Page, FlowDocument, or ResourceDictionary to a project, the Build Action for the markup file will default to Page.

在编译具有 Page 项的项目时,XAMLXAML 项将转换为二进制格式,并编译到关联的程序集中。When a project with Page items is compiled, the XAMLXAML items are converted to binary format and compiled into the associated assembly. 因此,可以像使用典型的资源文件一样使用这些文件。Consequently, these files can be used in the same way as typical resource files.

备注

如果 XAMLXAML 文件配置为 Resource 项,但没有代码隐藏文件,则原始 XAMLXAML 会编译为程序集,而不是原始 XAMLXAML的二进制版本。If a XAMLXAML file is configured as a Resource item, and does not have a code-behind file, the raw XAMLXAML is compiled into an assembly rather than a binary version of the raw XAMLXAML.

内容文件Content Files

内容文件与可执行程序集一起分发为松散文件。A content file is distributed as a loose file alongside an executable assembly. 虽然它们不编译到程序集内,但编译程序集时所使用的元数据建立了与每个内容文件的关联。Although they are not compiled into an assembly, assemblies are compiled with metadata that establishes an association with each content file.

如果应用程序需要一组特定的应用程序数据文件,并且你希望能够更新这些文件,而无需重新编译使用它们的程序集,应使用内容文件。You should use content files when your application requires a specific set of application data files that you want to be able to update without recompiling the assembly that consumes them.

配置内容文件Configuring Content Files

若要将内容文件添加到项目中,应用程序数据文件必须作为 Content 项包含在内。To add a content file to a project, an application data file must be included as a Content item. 此外,由于不会将内容文件直接编译到程序集中,因此需要设置 MSBuild CopyToOutputDirectory metadata 元素,以指定将内容文件复制到相对于生成的程序集的位置。Furthermore, because a content file is not compiled directly into the assembly, you need to set the MSBuild CopyToOutputDirectory metadata element to specify that the content file is copied to a location that is relative to the built assembly. 如果希望在每次生成项目时将资源复制到生成输出文件夹,请使用 Always 值设置 CopyToOutputDirectory 元数据元素。If you want the resource to be copied to the build output folder every time a project is built, you set the CopyToOutputDirectory metadata element with the Always value. 否则,你可以通过使用 PreserveNewest 值来确保只将最新版本的资源复制到生成输出文件夹。Otherwise, you can ensure that only the newest version of the resource is copied to the build output folder by using the PreserveNewest value.

下面演示的是一个配置为内容文件的文件,此内容文件只有在将新版本的资源添加到项目时才会复制到生成输出文件夹。The following shows a file that is configured as a content file which is copied to the build output folder only when a new version of the resource is added to the project.

<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相同)。In Visual Studio, you create a content file by adding a file to a project and setting its Build Action to Content, and set its Copy to Output Directory to Copy always (same as Always) and Copy if newer (same as PreserveNewest).

生成项目时,会将 AssemblyAssociatedContentFileAttribute 属性编译到每个内容文件的程序集的元数据中。When the project is built, an AssemblyAssociatedContentFileAttribute attribute is compiled into the metadata of the assembly for each content file.

[assembly: AssemblyAssociatedContentFile("ContentFile.xaml")]

AssemblyAssociatedContentFileAttribute 的值表示内容文件相对于其在项目中的位置的路径。The value of the AssemblyAssociatedContentFileAttribute implies the path to the content file relative to its position in the project. 例如,如果内容文件位于项目子文件夹中,则其他路径信息将合并到 AssemblyAssociatedContentFileAttribute 值中。For example, if a content file was located in a project subfolder, the additional path information would be incorporated into the AssemblyAssociatedContentFileAttribute value.

[assembly: AssemblyAssociatedContentFile("Resources/ContentFile.xaml")]

AssemblyAssociatedContentFileAttribute 值也是内容文件在生成输出文件夹中的路径的值。The AssemblyAssociatedContentFileAttribute value is also the value of the path to the content file in the build output folder.

使用内容文件Using Content Files

若要加载内容文件,可以调用 Application 类的 GetContentStream 方法,同时传递标识所需内容文件的包 URI。To load a content file, you can call the GetContentStream method of the Application class, passing a pack URI that identifies the desired content file. GetContentStream 返回一个 StreamResourceInfo 对象,该对象将内容文件作为 Stream 公开,并描述其内容类型。GetContentStream returns a StreamResourceInfo object, which exposes the content file as a Stream and describes its content type.

例如,下面的代码演示如何使用 GetContentStream 加载 Page 的内容文件,并将其设置为 FramepageFrame)的内容。As an example, the following code shows how to use GetContentStream to load a Page content file and set it as the content of a 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时,需要执行其他工作,将其转换为你要将其设置到的属性的类型。While calling GetContentStream gives you access to the Stream, you need to perform the additional work of converting it to the type of the property that you'll be setting it with. 相反,你可以让 WPF 通过使用代码将资源文件直接加载到类型的属性中来处理 Stream 的打开和转换。Instead, you can let WPF take care of opening and converting the Stream by loading a resource file directly into the property of a type using code.

下面的示例演示如何使用代码将 Page 直接加载到 FramepageFrame)。The following example shows how to load a Page directly into a Frame (pageFrame) using code.

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

下面的示例是与上例等效的标记。The following example is the markup equivalent of the preceding example.

<Frame Name="pageFrame" Source="PageContentFile.xaml" />

源站点文件Site of Origin Files

资源文件与一起分发的程序集具有显式关系,如 AssemblyAssociatedContentFileAttribute所定义。Resource files have an explicit relationship with the assemblies that they are distributed alongside, as defined by the AssemblyAssociatedContentFileAttribute. 但是,有些情况下可能需要在程序集和应用程序数据文件之间建立隐式关系或不存在的关系,这些情况包括:But, there are times when you may want to establish either an implicit or non-existent relationship between an assembly and an application data file, including when:

  • 文件在编译时不存在。A file doesn't exist at compile time.

  • 在运行之前不知道程序集将需要哪些文件。You don't know what files your assembly will require until run time.

  • 希望能够更新文件,无需重新编译与这些文件关联的程序集。You want to be able to update files without recompiling the assembly that they are associated with.

  • 应用程序使用大型数据文件(如音频和视频),并且你希望仅在用户选择下载时才下载这些文件。Your application uses large data files, such as audio and video, and you only want users to download them if they choose to.

可以通过使用传统的 URI 方案(例如 file:///和 http://方案)加载这些类型的文件。It is possible to load these types of files by using traditional URI schemes, such as the file:/// and http:// schemes.

<Image Source="file:///C:/DataFile.bmp" />
<Image Source="http://www.datafilewebsite.com/DataFile.bmp" />

但是,file:/// 和 http:// 方案要求应用程序具有完全信任。However, the file:/// and http:// schemes require your application to have full trust. 如果你的应用程序是从 Internet 或 intranet 启动的 XAML 浏览器应用程序(XBAP),并且该应用程序只请求从这些位置启动的应用程序允许的权限集,则松散文件只能从应用程序的源站点(启动位置)。If your application is a XAML browser application (XBAP) that was launched from the Internet or intranet, and it requests only the set of permissions that are allowed for applications launched from those locations, loose files can only be loaded from the application's site of origin (launch location). 此类文件称为源站点文件。Such files are known as site of origin files.

虽然源站点文件并不仅限于部分信任应用程序,但这些文件是部分信任应用程序的唯一选择。Site of origin files are the only option for partial trust applications, although are not limited to partial trust applications. 完全信任应用程序可能仍然需要加载它们在生成时所不知道的应用程序数据文件;但是完全信任应用程序可以使用 file:///,应用程序数据文件很可能将安装在该应用程序程序集所在的文件夹或其子文件夹中。Full trust applications may still need to load application data files that they do not know about at build time; while full trust applications could use file:///, it is likely that the application data files will be installed in the same folder as, or a subfolder of, the application assembly. 在此情况下,使用源站点引用比使用 file:/// 更加容易,因为使用 file:/// 需要找出文件的完整路径。In this case, using site of origin referencing is easier than using file:///, because using file:/// requires you to work out the full path the file.

备注

源站点文件不与客户端计算机上的 XAML 浏览器应用程序(XBAP)缓存,而内容文件为。Site of origin files are not cached with an XAML browser application (XBAP) on a client machine, while content files are. 因此,只有在专门请求下载源站点文件时,才会下载它们。Consequently, they are only downloaded when specifically requested. 如果 XAML 浏览器应用程序(XBAP)应用程序包含大型媒体文件,则将其配置为源站点文件意味着初始应用程序的启动速度要快得多,并且仅按需下载这些文件。If an XAML browser application (XBAP) application has large media files, configuring them as site of origin files means the initial application launch is much faster, and the files are only downloaded on demand.

配置源站点文件Configuring Site of Origin Files

如果源站点文件在编译时不存在或未知,则需要使用传统的部署机制来确保在运行时可以使用所需的文件,包括使用 XCopy 命令行程序或 Microsoft Windows Installer。If your site of origin files are non-existent or unknown at compile time, you need to use traditional deployment mechanisms for ensuring the required files are available at run time, including using either the XCopy command-line program or the Microsoft Windows Installer.

如果你在编译时知道想要位于源站点的文件,但仍希望避免显式依赖项,则可以将这些文件作为 None 项添加到 MSBuild 项目。If you do know at compile time the files that you would like to be located at the site of origin, but still want to avoid an explicit dependency, you can add those files to an MSBuild project as None item. 与内容文件一样,需要设置 MSBuild CopyToOutputDirectory 特性,以指定将源站点文件复制到相对于生成的程序集的位置,方法是指定 Always 值或 PreserveNewest 值。As with content files, you need to set the MSBuild CopyToOutputDirectory attribute to specify that the site of origin file is copied to a location that is relative to the built assembly, by specifying either the Always value or the PreserveNewest value.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >  
  ...  
  <None Include="PageSiteOfOriginFile.xaml">  
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>  
  </None>  
  ...  
</Project>  

备注

在 Visual Studio 中,你可以通过将文件添加到项目并将其 Build Action 设置为 None来创建源站点文件。In Visual Studio, you create a site of origin file by adding a file to a project and setting its Build Action to None.

生成项目时,MSBuild 会将指定的文件复制到生成输出文件夹。When the project is built, MSBuild copies the specified files to the build output folder.

使用源站点文件Using Site of Origin Files

若要加载源站点文件,可以调用 Application 类的 GetRemoteStream 方法,同时传递标识所需的源站点文件的包 URI。To load a site of origin file, you can call the GetRemoteStream method of the Application class, passing a pack URI that identifies the desired site of origin file. GetRemoteStream 返回一个 StreamResourceInfo 对象,该对象将源站点文件作为 Stream 公开,并描述其内容类型。GetRemoteStream returns a StreamResourceInfo object, which exposes the site of origin file as a Stream and describes its content type.

例如,下面的代码演示如何使用 GetRemoteStream 加载 Page 的源站点文件,并将其设置为 FramepageFrame)的内容。As an example, the following code shows how to use GetRemoteStream to load a Page site of origin file and set it as the content of a 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时,需要执行其他工作,将其转换为你要将其设置到的属性的类型。While calling GetRemoteStream gives you access to the Stream, you need to perform the additional work of converting it to the type of the property that you'll be setting it with. 相反,你可以让 WPF 通过使用代码将资源文件直接加载到类型的属性中来处理 Stream 的打开和转换。Instead, you can let WPF take care of opening and converting the Stream by loading a resource file directly into the property of a type using code.

下面的示例演示如何使用代码将 Page 直接加载到 FramepageFrame)。The following example shows how to load a Page directly into a Frame (pageFrame) using code.

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

下面的示例是与上例等效的标记。The following example is the markup equivalent of the preceding example.

<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />

更改生成类型后重新生成Rebuilding After Changing Build Type

在更改应用程序数据文件的生成类型后,需要重新生成整个应用程序以确保应用这些更改。After you change the build type of an application data file, you need to rebuild the entire application to ensure those changes are applied. 如果只生成应用程序,则不会应用更改。If you only build the application, the changes are not applied.

另请参阅See also