Ресурсы, Содержимое и Файлы данных WPF-приложения
Приложения Microsoft Windows обычно зависят от файлов с неисполняемыми данными, такими как Extensible Application Markup Language (XAML), изображения, видео и аудио. Windows Presentation Foundation (WPF) предоставляет специальную поддержку при настройке, распознавании и использовании этих типов файлов данных, называемых файлами данных приложения. Эта поддержка относится к определенному набору типов файлов данных приложения, включая:
Файлы ресурсов: файлы данных, скомпилированные либо в исполняемую, либо в библиотечную сборку WPF.
Файлы содержимого: автономные файлы данных, имеющие явную связь с исполняемой сборкой WPF.
Файлы исходного узла: автономные файлы данных, не имеющие связи с исполняемой сборкой WPF.
Важным различием между этими тремя типами файлов является то, что файлы ресурсов и содержимого известны во время построения; сборка имеет явно заданные сведения о них. Однако сборка может вообще не иметь сведений о файлах исходного узла или иметь неявные сведения через пакетную ссылку uniform resource identifier (URI). В этом случае нет гарантии, что файл начального узла, на который указывает ссылка, действительно существует.
Для ссылки на файлы данных приложения Windows Presentation Foundation (WPF) использует схему пакета uniform resource identifier (URI), которая подробно описана в разделе URI типа "pack" в WPF).
В этом разделе описана настройка и использование файлов данных приложения.
В этом разделе содержатся следующие подразделы.
- Файлы ресурсов
- Файлы содержимого
- Файлы исходного узла
- Повторное построение после изменения типа построения
- Связанные разделы
Файлы ресурсов
Если файл данных приложения должен быть всегда доступен приложению, то единственным способом, гарантирующим доступность, является компилирование его в основную исполняемую сборку приложения или одну из его сборок, на которую указывает ссылка. Этот тип файлов данных приложения называется файлом ресурса.
Файлы ресурсов следует использовать в следующих случаях.
Не требуется обновлять содержимое этого файла ресурсов после компилирования сборки.
Требуется упростить распространение приложения, уменьшив количество зависимостей между файлами.
Файлы данных приложения должны быть локализуемыми (см. раздел Общие сведения о глобализации и локализации WPF).
Примечание |
---|
Словари ресурсов (файлы XAML с ResourceDictionary в качестве элемента верхнего уровня) не являются файлами ресурсов WPF; хотя файлы ресурсов WPF могут являться словарями ресурсов, словарь ресурсов может не быть файлом ресурсов (см. раздел ResourceDictionary). Кроме того, файлы ресурсов WPF отличаются от ресурсов внедренного или связанного типа, которые можно настроить с помощью основной поддержки ресурсов сборки .NET Framework (см. раздел Управление ресурсами приложения).В то время как файлы ресурсов WPF используют основную поддержку внедренных ресурсов .NET Framework, возможность доступа к файлам ресурсов WPF с помощью пакетов URIs является намного более простой, чем с помощью пространств имен. |
Настройка файлов ресурсов
В WPF файл ресурсов является файлом, который включен в проект Microsoft build engine (MSBuild) в качестве элемента Resource.
<Project "xmlns=https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>
Примечание |
---|
В Microsoft Visual Studio файл ресурсов создается путем добавления файла к проекту и задания для его свойства Build Action значения Resource. |
После создания проекта MSBuild компилирует ресурс в сборку.
Использование файлов ресурсов
Чтобы загрузить файл ресурсов, можно вызвать метод GetResourceStream класса Application при передаче пакета URI, идентифицирующего нужный файл ресурсов. Метод GetResourceStream возвращает объект StreamResourceInfo, который предоставляет файл ресурсов в качестве объекта Stream и описывает тип его содержимого.
Например, следующий фрагмент кода показывает использование GetResourceStream для загрузки файла ресурсов Page и установки его как содержимого 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;
В то время как вызов GetResourceStream предоставляет доступ к Stream, необходимо выполнить дополнительные действия по преобразованию его к типу свойства, с помощью которого он будет устанавливаться. Вместо этого можно позволить WPF позаботиться об открытии и преобразовании Stream путем загрузки файла ресурсов с помощью кода непосредственно в свойство типа.
В следующем примере показана загрузка Page с помощью кода непосредственно в Frame (pageFrame).
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;
В следующем примере разметка эквивалентна разметке в предыдущем примере.
<Frame Name="pageFrame" Source="PageResourceFile.xaml" />
Файлы кода приложения как файлы ресурсов
На специальный набор файлов кода приложения WPF можно ссылаться с помощью пакета URIs, включая окна, страницы, документы нефиксированного формата и словари ресурсов. Например, можно задать свойство Application.StartupUri с помощью пакета URI, ссылающегося на окно или страницу, которую требуется загрузить при запуске приложения.
<Application
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="SOOPage.xaml" />
Это можно сделать, когда файл XAML включен в проект Microsoft build engine (MSBuild) в качестве элемента Page.
<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
Примечание |
---|
В Visual Studio при добавлении к проекту нового Window, NavigationWindowPage, FlowDocument или ResourceDictionary Build Action для файла разметки по умолчанию устанавливается в значение Page. |
При компиляции проекта с элементами Page, элементы XAML преобразуются в двоичный формат и компилируются в связанную сборку. Следовательно, эти файлы могут быть использованы так же, как обычные файлы ресурсов.
Примечание |
---|
Если файл XAML настроен в качестве элемента Resource и не имеет файла кода программной части, в сборку компилируется необработанный XAML, а не двоичная версия необработанного XAML. |
Файлы содержимого
Файл содержимого рассматривается исполняемой сборкой как свободный файл. Несмотря на то что они не компилируются в сборку, сборки компилируются с метаданными, устанавливающими связь с каждым файлом содержимого.
Файлы содержимого необходимо использовать, когда приложению требуется определенный набор файлов данных приложения, которые необходимо обновлять без перекомпиляции использующей их сборки.
Настройка файлов содержимого
Чтобы добавить файл содержимого в проект, файл данных приложения должен быть включен как элемент Content. Кроме того, так как файл содержимого не компилируется непосредственно в сборку, необходимо задать MSBuild CopyToOutputDirectory элемента метаданных, чтобы указать, что файл содержимого копируется в местоположение, имеющее отношение к сборке. Если требуется, чтобы ресурс копировался в папку назначения при каждом построении проекта, установите для элемента метаданных CopyToOutputDirectory значение Always. Также можно убедиться, что только новая версия ресурса копируется в папку назначения, с помощью значения PreserveNewest.
Ниже приведен файл, настроенный в качестве файла содержимого, который копируется в папку назначения только при добавлении в проект новой версии ресурса.
<Project xmlns="https://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 также является значением пути к файлу содержимого в папке назначения построения.
Использование файлов содержимого
Чтобы загрузить файл содержимого, можно вызвать метод GetContentStream класса Application при передаче пакета URI, идентифицирующего нужный файл содержимого. Метод GetContentStream возвращает объект StreamResourceInfo, который предоставляет файл содержимого в качестве объекта Stream и описывает тип его содержимого.
Например, следующий фрагмент кода показывает использование GetContentStream для загрузки файла содержимого Page и задания его в качестве содержимого 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;
В то время как вызов GetContentStream предоставляет доступ к Stream, необходимо выполнить дополнительные действия по преобразованию его к типу свойства, с помощью которого он будет устанавливаться. Вместо этого можно позволить WPF позаботиться об открытии и преобразовании Stream путем загрузки файла ресурсов с помощью кода непосредственно в свойство типа.
В следующем примере показана загрузка Page с помощью кода непосредственно в Frame (pageFrame).
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;
В следующем примере разметка эквивалентна разметке в предыдущем примере.
<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 browser application (XBAP) было запущено из Интернета или интрасети и оно запрашивает только набор разрешений, предоставляемых приложениям, запускаемым таким образом, свободные файлы могут быть загружены только с исходного узла приложения (расположения запуска). Такие файлы называются файлами исходного узла.
В приложениях с частичным доверием используются только файлы исходного узла, однако сами файлы этого типа могут использоваться и в других приложениях. Приложениям с полным доверием по-прежнему может требоваться загрузить файлы данных приложения, о которых они не знают во время построения. Хотя приложения с полным доверием могут использовать file:///, вполне вероятно, что файлы данных приложения будут установлены в ту же папку, что и сборка приложения, или вложенную папку. В этом случае использование ссылки на исходный сайт является более простым способом, чем использование file:///, так как при использовании file:/// требуется указывать полный путь к файлу.
Примечание |
---|
Файлы исходного узла не кэшируются с XAML browser application (XBAP) на клиентском компьютере, в отличие от файлов содержимого.Поэтому они загружаются только по специальному запросу.Если приложение XAML browser application (XBAP) содержит файлы мультимедиа большого объема, то их настройка в качестве файлов исходного узла намного ускоряет начальный запуск приложения, а файлы будут загружаться только по требованию. |
Настройка файлов исходного узла
Если файлы исходного узла не существуют или неизвестны во время компиляции, необходимо использовать традиционные средства для обеспечения доступности необходимых файлов во время выполнения, включая использование либо программы командной строки XCopy, либо Microsoft Windows Installer.
Если во время компиляции известны файлы, которые должны быть расположены на исходном узле, но все еще требуется избежать явных зависимостей, то можно добавить эти файлы в проект Microsoft build engine (MSBuild) в качестве элемента None. Как и для файлов содержимого, необходимо установить атрибут MSBuild CopyToOutputDirectory, чтобы указать, что файл исходного узла скопируется в местоположение, имеющее отношение к сборки, указав значение Always или PreserveNewest.
<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
Примечание |
---|
В Visual Studio файл исходного узла создается путем добавления файла к проекту и установления для его Build Action значения None. |
При построении проекта MSBuild копирует указанные файлы в папку назначения.
Использование файлов исходного сайта
Чтобы загрузить файл исходного сайта, можно вызвать метод GetRemoteStream класса Application при передаче пакета URI, идентифицирующего нужный файл исходного сайта. Метод GetRemoteStream возвращает объект StreamResourceInfo, который предоставляет файл исходного сайта в качестве объекта Stream и описывает тип его содержимого.
Например, следующий фрагмент кода иллюстрирует использование GetRemoteStream для загрузки файла исходного узла Page и установки его в качестве содержимого 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;
В то время как вызов GetRemoteStream предоставляет доступ к Stream, необходимо выполнить дополнительные действия по преобразованию его к типу свойства, с помощью которого он будет устанавливаться. Вместо этого можно позволить WPF позаботиться об открытии и преобразовании Stream путем загрузки файла ресурсов с помощью кода непосредственно в свойство типа.
В следующем примере показана загрузка Page с помощью кода непосредственно в Frame (pageFrame).
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;
В следующем примере разметка эквивалентна разметке в предыдущем примере.
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
Повторное построение после изменения типа построения
После изменения типа построения файла данных приложения необходимо осуществить повторную сборку всего приложения для применения изменений. Если просто выполнить построение приложения, изменения применяться не будут.