Archivos de recursos, contenido y datos de aplicaciones de WPF
Las aplicaciones para Microsoft Windows suelen depender de archivos que contienen datos no ejecutables, como Extensible Application Markup Language (XAML), imágenes, vídeo y audio. Windows Presentation Foundation (WPF) proporciona 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 archivos de datos de aplicación, como:
Archivos de recursos: archivos de datos que se generan en un ejecutable o en un ensamblado de biblioteca de WPF.
Archivos de contenido: archivos de datos independientes que tienen una asociación explícita con un ensamblado ejecutable de WPF.
Archivos de sitio de origen: archivos de datos independientes que no tienen ninguna asociación con un ensamblado ejecutable de WPF.
Hay una diferencia importante entre estos tres tipos de archivos: los archivos de recursos y los archivos de contenido se conocen en tiempo de compilación; un ensamblado tiene conocimiento explícito de ellos. En el caso de los archivos de sitio de origen, sin embargo, es posible que el ensamblado no tenga conocimiento de ellos o tenga un conocimiento implícito a través de una referencia de pack uniform resource identifier (URI); en este último caso, no hay ninguna garantía de que exista realmente el archivo de sitio de origen al que se hace referencia.
Para hacer referencia a los archivos de datos de aplicación, Windows Presentation Foundation (WPF) utiliza el esquema de pack uniform resource identifier (URI), que se describe detalladamente en Empaquetar URI en WPF.
En este tema se describe cómo configurar y utilizar los archivos de datos de aplicación.
Este tema contiene las secciones siguientes.
- Archivos de recursos
- Archivos de contenido
- Archivos de sitio de origen
- Volver a generar después de cambiar el tipo de compilación
- Temas relacionados
Archivos de recursos
Si un archivo de datos de aplicación debe estar siempre disponible para una aplicación, la única manera de garantizar la disponibilidad es generarlo en el ensamblado ejecutable principal de una aplicación o en uno de los ensamblados a los que hace referencia. Este tipo de archivo de datos de aplicación se conoce como archivo de recursos.
Los archivos de recursos deben usarse cuando:
No es necesario actualizar el contenido del archivo de recursos una vez generado en un ensamblado.
Se desea simplificar la distribución de la aplicación reduciendo el número de dependencias de archivo.
El archivo de datos de aplicación debe ser localizable (vea Información general sobre la localización y globalización de WPF).
Nota |
---|
Los diccionarios de recursos (archivos XAML con ResourceDictionary como su elemento de nivel superior) no son archivos de recursos de WPF; aunque los archivos de recursos de WPF pueden ser diccionarios de recursos, un diccionario de recursos no tiene que ser necesariamente un archivo de recursos (vea ResourceDictionary). Además, los archivos de recursos de WPF no son lo mismo que el tipo de recursos incrustado o vinculado que se puede configurar mediante la compatibilidad básica de .NET Framework con los recursos de ensamblado (vea Administrar los recursos de la aplicación).Si bien los archivos de recursos de WPF aprovechan la compatibilidad básica con los recursos incrustados de .NET Framework, el acceso a los archivos de recursos de WPF mediante pack URIs resulta más fácil que el uso de espacios de nombres. |
Configurar archivos de recursos
En WPF, un archivo de recursos es un archivo que está incluido en un proyecto de Microsoft build engine (MSBuild) como un elemento Resource.
<Project "xmlns=https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>
Nota |
---|
En Microsoft Visual Studio, se crea un archivo de recursos agregando un archivo a un proyecto y estableciendo el valor de Build Action en Resource. |
Una vez generado el proyecto, MSBuild genera el recurso en el ensamblado.
Usar archivos de recursos
Para cargar un archivo de recursos, puede llamar al método GetResourceStream de la clase Application, pasando un pack URI que identifique el archivo de recursos deseado. GetResourceStream devuelve un objeto StreamResourceInfo, que expone el archivo de recursos como un objeto Stream y describe su tipo de contenido.
Como ejemplo, en el código siguiente se muestra cómo utilizar GetResourceStream para cargar un archivo de recursos Page y establecerlo como contenido de un control Frame (pageFrame):
' 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
// 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;
Aunque al llamar a GetResourceStream se obtiene acceso a Stream, debe realizar el trabajo adicional de convertirlo en el tipo de la propiedad con la que lo establecerá. Como alternativa, puede dejar que WPF se ocupe de abrir y convertir el objeto Stream cargando un archivo de recursos directamente en la propiedad de un tipo mediante código.
En el ejemplo siguiente, se muestra cómo se carga un control Page directamente en un control Frame (pageFrame) mediante código.
Dim pageUri As New Uri("/PageResourceFile.xaml", UriKind.Relative)
Me.pageFrame.Source = pageUri
Uri pageUri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
El ejemplo siguiente es el equivalente en marcado 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 utilizando pack URIs, incluidos documentos dinámicos, ventanas, páginas y diccionarios de recursos. Por ejemplo, puede establecer la propiedad Application.StartupUri con un pack URI que hace referencia a la ventana o página que desee cargar cuando se inicie una aplicación.
<Application
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="SOOPage.xaml" />
Puede hacer esto cuando se incluye un archivo XAML en un proyecto de Microsoft build engine (MSBuild) como un elemento Page.
<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
Nota |
---|
En Visual Studio, agregue un nuevo objeto Window, NavigationWindow, Page, FlowDocument o ResourceDictionary a un proyecto; el valor predeterminado de Build Action para el archivo de marcado será Page. |
Cuando se genera un proyecto con elementos Page, los elementos XAML se convierten al formato binario y se generan en el ensamblado asociado. Por consiguiente, estos archivos se pueden utilizar de la misma manera 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 código XAML sin formato se generará en un ensamblado en lugar de una versión binaria del código XAML sin formato. |
Archivos de contenido
Un archivo de contenido se distribuye como un archivo separado junto a un ensamblado ejecutable. Aunque no estén generados en un ensamblado, los ensamblados se generan con metadatos que establecen una asociación con cada archivo de contenido.
Se recomienda utilizar archivos de contenido cuando la aplicación requiere un conjunto concreto de archivos de datos de aplicación que se desee poder actualizar sin tener que volver a generar el ensamblado que los consume.
Configurar archivos de contenido
Para agregar un archivo de contenido a un proyecto, se debe incluir un archivo de datos de aplicación como un elemento Content. Además, dado que un archivo de contenido no se genera directamente en el ensamblado, es necesario establecer el elemento de metadatos CopyToOutputDirectory de MSBuild para especificar que el archivo de contenido se copie en una ubicación relativa al ensamblado generado. Si desea que el recurso se copie en la carpeta de resultados de la compilación cada vez que se genere un proyecto, establezca el elemento de metadatos CopyToOutputDirectory en el valor Always. De lo contrario, para asegurarse de que sólo se copie la versión más reciente del recurso en la carpeta de resultados de la compilación, use el valor PreserveNewest.
A continuación se muestra un archivo configurado como archivo de contenido que sólo se copia en la carpeta de resultados de la compilación cuando se agrega al proyecto una nueva versión del recurso.
<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Content Include="ContentFile.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...
</Project>
Nota |
---|
En Visual Studio, puede crear un archivo de contenido agregando un archivo a un proyecto y estableciendo el valor de Build Action en Content; establezca el valor de Copy to Output Directory en Copy always (es lo mismo que Always) y Copy if newer (es lo mismo que PreserveNewest). |
Cuando se genera el proyecto, 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 con respecto a su posición en el proyecto. Por ejemplo, si un archivo de contenido se encontrara en una subcarpeta del proyecto, la información adicional de ruta de acceso se incorporaría en el valor de 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 resultados de la compilación.
Utilizar archivos de contenido
Para cargar un archivo de contenido, puede llamar al método GetContentStream de la clase Application, pasando un pack URI que identifique el archivo de contenido deseado. GetContentStream devuelve un objeto StreamResourceInfo, que expone el archivo de contenido como un objeto Stream y describe su tipo de contenido.
Como ejemplo, en el código siguiente se muestra cómo utilizar GetContentStream para cargar un archivo de contenido Page y establecerlo como contenido de un control Frame (pageFrame).
' 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
// 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;
Aunque al llamar a GetContentStream se obtiene acceso a Stream, debe realizar el trabajo adicional de convertirlo en el tipo de la propiedad con la que lo establecerá. Como alternativa, puede dejar que WPF se ocupe de abrir y convertir el objeto Stream cargando un archivo de recursos directamente en la propiedad de un tipo mediante código.
En el ejemplo siguiente, se muestra cómo se carga un control Page directamente en un control Frame (pageFrame) mediante código.
Dim pageUri As New Uri("/PageContentFile.xaml", UriKind.Relative)
Me.pageFrame.Source = pageUri
Uri pageUri = new Uri("/PageContentFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
El ejemplo siguiente es el equivalente en marcado del ejemplo anterior.
<Frame Name="pageFrame" Source="PageContentFile.xaml" />
Archivos de sitio de origen
Los archivos de recursos tienen una relación explícita con los ensamblados junto a los que se distribuyen, según lo definido en AssemblyAssociatedContentFileAttribute. No obstante, habrá ocasiones en las que quizá desee establecer una relación implícita o inexistente entre un ensamblado y un archivo de datos de aplicación, por ejemplo cuando:
Un archivo no exista en tiempo de compilación.
No sepa qué archivos necesitará el ensamblado hasta el tiempo de ejecución.
Desee poder actualizar los archivos sin tener que volver a generar el ensamblado al que están asociados.
La aplicación utilice archivos de datos grandes, como los de audio y vídeo, y desee que los usuarios los descarguen sólo si así lo eligen.
Es posible cargar estos tipos de archivo utilizando 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 sea de plena confianza. Si la aplicación es una aplicación XAML browser application (XBAP) iniciada desde Internet o desde una intranet y solicita solamente el conjunto de permisos que se permiten para las aplicaciones iniciadas desde esas ubicaciones, los archivos separados solamente se podrán cargar desde el sitio de origen de la aplicación (ubicación de inicio). Esos archivos se conocen como archivos de sitio de origen.
Los archivos de sitio de origen son la única opción para las aplicaciones de confianza parcial, aunque no se limitan a ellas. Puede que las aplicaciones de plena confianza necesiten cargar archivos de datos de aplicación que desconocen en tiempo de compilación; aunque las aplicaciones de plena confianza podrían utilizar file:///, es probable que los archivos de datos de aplicación se instalen en la misma carpeta o en una subcarpeta del ensamblado de la aplicación. En este caso, el uso de referencias al sitio de origen es más fácil que el uso de file:/// porque en este último caso es necesario especificar la ruta de acceso completa al archivo.
Nota |
---|
A diferencia de los archivos de contenido, los archivos de sitio de origen no se almacenan en la memoria caché con una aplicación XAML browser application (XBAP) en un equipo cliente.Por consiguiente, se descargan sólo cuando se solicita específicamente su descarga.Si una aplicación XAML browser application (XBAP) tiene archivos multimedia grandes, configurarlos como archivos de sitio de origen significa que el inicio de la aplicación será mucho más rápido y que los archivos solamente se descargarán a petición. |
Configurar archivos de sitio de origen
Si los archivos de sitio de origen son inexistentes o se desconocen en tiempo de compilación, necesitará utilizar los mecanismos de distribución tradicionales para asegurarse de que los archivos necesarios están disponibles en tiempo de ejecución, como el programa de línea de comandos XCopy o Microsoft Windows Installer.
Si desconoce en tiempo de compilación los archivos que deben encontrarse en el sitio de origen, pero aún desea evitar dependencias explícitas, puede agregar esos archivos a un proyecto de Microsoft build engine (MSBuild) como elemento None. Al igual que en el caso de los archivos de contenido, es necesario establecer el atributo MSBuild CopyToOutputDirectory para especificar que el archivo de sitio de origen se copie en una ubicación relativa al ensamblado generado, especificando el valor Always o el valor PreserveNewest.
<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
Nota |
---|
En Visual Studio, se crea un archivo de sitio de origen agregando un archivo a un proyecto y estableciendo el valor de Build Action en None. |
Al generar el proyecto, MSBuild copia los archivos especificados en la carpeta de resultados de la compilación.
Utilizar archivos de sitio de origen
Para cargar un archivo de sitio de origen, puede llamar al método GetRemoteStream de la clase Application, pasando un pack URI que identifique el archivo de sitio de origen deseado. GetRemoteStream devuelve un objeto StreamResourceInfo, que expone el archivo de sitio de origen como Stream y describe su tipo de contenido.
Como ejemplo, en el código siguiente se muestra cómo utilizar GetRemoteStream para cargar un archivo de sitio de origen Page y establecerlo como contenido de un control Frame (pageFrame).
' 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
// 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;
Aunque al llamar a GetRemoteStream se obtiene acceso a Stream, debe realizar el trabajo adicional de convertirlo en el tipo de la propiedad con la que lo establecerá. Como alternativa, puede dejar que WPF se ocupe de abrir y convertir el objeto Stream cargando un archivo de recursos directamente en la propiedad de un tipo mediante código.
En el ejemplo siguiente, se muestra cómo se carga un control Page directamente en un control Frame (pageFrame) mediante código.
Dim pageUri As New Uri("pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml", UriKind.Absolute)
Me.pageFrame.Source = pageUri
Uri pageUri = new Uri("pack://siteoforigin:,,,/SiteOfOriginFile.xaml", UriKind.Absolute);
this.pageFrame.Source = pageUri;
El ejemplo siguiente es el equivalente en marcado del ejemplo anterior.
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
Volver a generar 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, debe volver a generar la aplicación completa para asegurarse de que se apliquen esos cambios. Si solamente genera la aplicación, no se aplicarán los cambios.