Archivos de recursos, contenido y datos de aplicaciones de WPF

Las aplicaciones de Microsoft Windows a menudo dependen de archivos que contienen datos no ejecutable, como lenguaje XAML, imágenes, vídeo y audio. Windows Presentation Foundation (WPF) ofrece una compatibilidad especial para configurar, identificar y utilizar estos tipos de archivos de datos, que se denominan archivos de datos de aplicación. Esta compatibilidad gira en torno a un conjunto específico de tipos de archivo de datos de aplicación, entre los que se incluyen:

  • Archivos de recursos: archivos de datos que se compilan en un ejecutable o un ensamblado de WPF de biblioteca.

  • Archivos de contenido: archivos de datos independientes que tienen una asociación explícita con un ensamblado de WPF ejecutable.

  • Sitio de archivos de origen: archivos de datos independientes que tienen una asociación con un ensamblado de WPF ejecutable.

Una diferencia importante entre estos tres tipos de archivos es que tanto los archivos de recursos como los archivos de contenido se conocen en el momento de la compilación; un ensamblado tiene un conocimiento explícito de ellos. Sin embargo, en el caso del sitio de los archivos de sitio, es posible que un ensamblado no tenga ningún conocimiento de ellos, o bien que tenga un conocimiento implícito a través de una referencia del identificador uniforme de recursos (URI) del paquete; en este último caso, no hay ninguna garantía de que el sitio del archivo de origen al que se hace referencia existe realmente.

Para hacer referencia a archivos de datos de aplicación, Windows Presentation Foundation (WPF) usa el esquema del identificador uniforme de recursos (URI) del paquete, que se describe con todo detalle en Pack URIs in Windows Presentation Foundation (Identificadores URI de paquetes en Windows Presentation Foundation).

En este tema se describe cómo configurar y usar archivos de datos de aplicaciones.

Archivos de recursos

Si un archivo de datos de la aplicación debe estar siempre disponible para una aplicación, la única forma de garantizar la disponibilidad es compilarlo en el ensamblado ejecutable principal de una aplicación o en uno de sus ensamblados referenciados. Este tipo de archivo de datos de aplicación se conoce como archivo de recursos.

Los archivos de recursos se deben usar cuando:

  • No es necesario actualizar el contenido del archivo de recursos después de que se compila en un ensamblado.

  • Desea simplificar la complejidad de la distribución de una aplicación mediante la reducción del número de dependencias de los archivos.

  • Es preciso que el archivo de datos de la aplicación se pueda localizar (consulte Información general sobre la globalización y la localización de WPF).

Nota:

Los archivos de recursos que se describen en esta sección son diferentes tanto de los que se describen en Recursos XAML como de los insertados o vinculados que se describen en Administración de los recursos de la aplicación (.NET).

Configuración de archivos de recursos

En WPF, un archivo de recursos es un archivo que se incluye en un proyecto de Microsoft Build Engine como un elemento de Resource.

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

Nota:

En Visual Studio, para crear un archivo de recursos se agrega un archivo a un proyecto y en Build Action se elige Resource.

Cuando se ha compila el proyecto, MSBuild compila el recurso en el ensamblado.

Uso de archivos de recursos

Para cargar un archivo de recursos, puede llamar al método GetResourceStream de la clase Application y pasar un URI de paquete que identifica el archivo de recursos deseado. GetResourceStream devuelve un objeto StreamResourceInfo, que expone el archivo de recursos como Stream y describe su tipo de contenido.

Por ejemplo, el código siguiente muestra cómo utilizar GetResourceStream para cargar un archivo de recursos de Page y establecerlo como contenido de 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

Aunque llamar a GetResourceStream proporciona acceso a Stream, es preciso realizar el trabajo adicional de convertirlo en el tipo de la propiedad con que lo establecerá. En su lugar, puede dejar que WPF se ocupe de abrir y convertir Stream cargando un archivo de recursos directamente en la propiedad de un tipo mediante código.

En el ejemplo siguiente se muestra cómo cargar Page directamente en Frame (pageFrame) mediante código.

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

El ejemplo siguiente es el equivalente de marcación del ejemplo anterior.

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

Archivos de código de aplicación como archivos de recursos

Se puede hacer referencia a un conjunto especial de archivos de código de aplicación de WPF mediante identificadores URI de paquete, que incluyen ventanas, páginas, documentos dinámicos y diccionarios de recursos. Por ejemplo, puede establecer la propiedad Application.StartupUri con un URI de paquete que haga referencia a la ventana o página que desea que se cargue cuando se inicia una aplicación.

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

Esto se puede hacer cuando se incluye un archivo XAML en un proyecto MSBuild como un elemento Page.

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

Nota:

En Visual Studio, se agrega una clase Window, NavigationWindow, Page, FlowDocument o ResourceDictionary nueva a un proyecto y el valor predeterminado de Build Action para el archivo de marcación será Page.

Cuando se compila un proyecto con elementos Page, los elementos XAML se convierten a formato binario y se compilan en el ensamblado asociado. Por consiguiente, estos archivos se pueden utilizar de la misma forma que los archivos de recursos típicos.

Nota:

Si un archivo XAML se configura como un elemento Resource y no tiene un archivo de código subyacente, el XAML sin formato se compila en un ensamblado, en lugar de una versión binaria del XAML sin formato.

Archivos de contenido

Un archivo de contenido se distribuye como un archivo dinámico junto a un ensamblado ejecutable. Aunque no se compilan en un ensamblado, los ensamblados se compilan con metadatos que establecen una asociación con cada archivo de contenido.

Los archivos de contenido se deben usar cuando la aplicación requiere un conjunto específico de archivos de datos de aplicación que desee poder actualizar sin volver a compilar el ensamblado que los consume.

Configuración de archivos de contenido

Para agregar un archivo de contenido a un proyecto, un archivo de datos de la aplicación debe incluirse como elemento Content. Además, dado que un archivo de contenido no se compila directamente en el ensamblado, es preciso establecer el elemento de metadatos CopyToOutputDirectory de MSBuild para especificar que el archivo de contenido se copia en una ubicación relativa al ensamblado generado. Si desea que el recurso se copie en la carpeta de salida de compilación cada vez que se compile un proyecto, establezca el elemento de metadatos CopyToOutputDirectory con el valor Always. De lo contrario, puede asegurarse de que solo la versión más reciente del recurso se copia en la carpeta de salida de compilación mediante el valor de PreserveNewest.

A continuación muestra un archivo que se configura como un archivo de contenido que se copia en la carpeta de salida de compilación solo cuando se agrega al proyecto una nueva versión del recurso.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >  
  ...  
  <ItemGroup>  
    <Content Include="ContentFile.xaml">  
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>  
    </Content>  
  </ItemGroup>  
  ...  
</Project>  

Nota:

En Visual Studio, cree un archivo de contenido agregando un archivo a un proyecto y estableciendo Build Action en Content y establezca sus Copy to Output Directory en Copy always (igual que Always) yCopy if newer (igual que PreserveNewest).

Cuando se compila el proyecto, también se compila un atributo AssemblyAssociatedContentFileAttribute en los metadatos del ensamblado para cada archivo de contenido.

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

El valor de AssemblyAssociatedContentFileAttribute implica la ruta de acceso al archivo de contenido en relación con su posición en el proyecto. Por ejemplo, si un archivo de contenido se encontraba en una subcarpeta del proyecto, la información de la ruta adicional se incorporaría al valor AssemblyAssociatedContentFileAttribute.

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

El valor de AssemblyAssociatedContentFileAttribute es también el valor de la ruta de acceso al archivo de contenido en la carpeta de salida de la compilación.

Uso de archivos de contenido

Para cargar un archivo de contenido, puede llamar al método GetContentStream de la clase Application y pasar un URI de paquete que identifica el archivo de contenido deseado. GetContentStream devuelve un objeto StreamResourceInfo, que expone el archivo de contenido como Stream y describe su tipo de contenido.

Por ejemplo, el código siguiente muestra cómo utilizar GetContentStream para cargar un archivo de contenido de Page y establecerlo como contenido de 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

Aunque llamar a GetContentStream proporciona acceso a Stream, es preciso realizar el trabajo adicional de convertirlo en el tipo de la propiedad con que lo establecerá. En su lugar, puede dejar que WPF se ocupe de abrir y convertir Stream cargando un archivo de recursos directamente en la propiedad de un tipo mediante código.

En el ejemplo siguiente se muestra cómo cargar Page directamente en Frame (pageFrame) mediante código.

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

El ejemplo siguiente es el equivalente de marcación del ejemplo anterior.

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

Sitio de archivos de origen

Los archivos de recursos tienen una relación explícita con los ensamblados en los que se distribuyen, tal como se define AssemblyAssociatedContentFileAttribute. Sin embargo, hay veces en las que puede desear establecer una relación implícita o inexistente entre un ensamblado y un archivo de datos de aplicación, incluyendo cuándo:

  • No existe un archivo en tiempo de compilación.

  • No sabe qué archivos requerirá el ensamblado hasta el tiempo de ejecución.

  • Desea poder actualizar los archivos sin volver a compilar el ensamblado al que están asociados.

  • La aplicación utiliza archivos de datos grandes, como audio y vídeo, y solo desea que los usuarios los descarguen si eligen hacerlo.

Es posible cargar estos tipos de archivos mediante esquemas de URI tradicionales, como los esquemas file:/// y http://.

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

Sin embargo, los esquemas file:/// y http:// requieren que la aplicación tenga plena confianza. Si la aplicación es una aplicación del explorador XAML (XBAP) que se inició desde Internet o una intranet, y solicita solo el conjunto de permisos para las aplicaciones iniciadas desde esas ubicaciones, los archivos dinámicos solo se pueden cargar del sitio de origen de la aplicación (ubicación de inicio). Estos archivos se denominan archivos del sitio de origen.

Los archivos del sitio de origen son la única opción para las aplicaciones de confianza parcial, aunque no se limitan a ese tipo de aplicaciones. Es posible que las aplicaciones de plena confianza aún necesiten cargar archivos de datos de aplicación que desconocen en tiempo de compilación; mientras que las aplicaciones de plena confianza pueden utilizar file:///, es probable que los archivos de datos de la aplicación se instalarán en la misma carpeta que el ensamblado de la aplicación, o en una subcarpeta de él. En este caso, es más sencillo usar la referencia del sitio de origen que file:///, ya que el uso de file:/// requiere que se determine la ruta de acceso completa del archivo.

Nota:

Los archivos de sitio de origen no se almacenan en la memoria caché con una aplicación del explorador XAML (XBAP) en un equipo cliente, mientras que los archivos de contenido se almacenan. Por consiguiente, sólo se descargan cuando se solicita específicamente. Si una aplicación del explorador XAML (XBAP) tiene archivos multimedia grandes, configurarlos como archivos de sitio de origen significa que el inicio de la aplicación se realiza mucho más rápidamente y los archivos solo se descargan a petición.

Configuración de archivos de sitio de origen

Si sus archivos de sitio de origen son inexistentes o desconocido en tiempo de compilación, es preciso que use mecanismos de implementación tradicionales para garantizar que los archivos requeridos están disponibles en tiempo de ejecución, lo que incluye el uso del programa de línea de comandos XCopy o Microsoft Windows Installer.

Si conoce en tiempo de compilación los archivos que desea que se encuentren en el sitio de origen, pero desea evitar una dependencia explícita, puede agregar dichos archivos a un proyecto de MSBuild como elemento None. Igual que sucede con los archivos de contenido, debe establecer el atributo CopyToOutputDirectory de MSBuild para especificar que el archivo de sitio de origen se copia en una ubicación relativa al ensamblado generado, para lo que se especifican el valor Always o el valor PreserveNewest.

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

Nota:

En Visual Studio, para crear un archivo de sitio de origen se agrega un archivo a un proyecto y en Build Action se elige None.

Cuando se compila el proyecto, MSBuild copia los archivos especificados en la carpeta de salida de compilación.

Uso de archivos del sitio de origen

Para cargar un archivo del sitio de origen puede llamar al método GetRemoteStream de la clase Application y pasar un URI de paquete que identifica el archivo del sitio de origen deseado. GetRemoteStream devuelve un objeto StreamResourceInfo, que expone el archivo del sitio de origen como Stream y describe su tipo de contenido.

Por ejemplo, el código siguiente muestra cómo utilizar GetRemoteStream para cargar un archivo del sitio de origen de Page y establecerlo como contenido de 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

Aunque llamar a GetRemoteStream proporciona acceso a Stream, es preciso realizar el trabajo adicional de convertirlo en el tipo de la propiedad con que lo establecerá. En su lugar, puede dejar que WPF se ocupe de abrir y convertir Stream cargando un archivo de recursos directamente en la propiedad de un tipo mediante código.

En el ejemplo siguiente se muestra cómo cargar Page directamente en Frame (pageFrame) mediante código.

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

El ejemplo siguiente es el equivalente de marcación del ejemplo anterior.

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

Nueva compilación después de cambiar el tipo de compilación

Después de cambiar el tipo de compilación de un archivo de datos de aplicación, es preciso volver a compilar toda la aplicación para asegurarse de que se aplican los cambios. Si solo compila la aplicación, no se aplican los cambios.

Vea también