Ресурсы, Содержимое и Файлы данных WPF-приложения
Приложения Microsoft Windows часто используют файлы, которые содержат неисполняемые данные, такие как XAML, изображения, видео и аудио. Windows Presentation Foundation (WPF) предоставляет специальную поддержку для настройки, распознавания и использовании этих типов файлов данных, которые называются файлами данных приложения. Эта поддержка относится к определенному набору типов файлов данных приложения, включая следующие:
Файлы ресурсов: Файлы данных, которые компилируются в исполняемый файл или библиотеку WPF.
Файлы содержимого: Автономные файлы данных, имеющие явную связь с исполняемой сборкой WPF.
Файлы исходного узла: Автономные файлы данных, которые не имеют никакой связи с исполняемой сборкой WPF.
Важным отличием между этими тремя типами файлов является то, что файлы ресурсов и файлы содержимого известны во время построения. Сборка содержит информацию о них. В случае файлов исходного узла, напротив, сборка может вообще не знать о них, или содержать неявные сведения через ссылки pack URI; в последнем случае нет никакой гарантии, что указанный файл исходного узла действительно существует.
Чтобы ссылаться на файлы данных приложения, Windows Presentation Foundation (WPF) использует схему pack URI, которая подробно описана в статье URI типа Pack в WPF).
В этом разделе описывается настройка и использование файлов данных приложения.
Файлы ресурсов
Если файл данных приложения всегда должен быть доступен для приложения, то единственный способ гарантировать доступность — скомпилировать его в главную исполняемую сборку приложения или в одну сборок, на которые она ссылается. Этот тип файлов данных приложения называется файл ресурсов.
Используйте файлы ресурсов, если:
Не требуется обновлять содержимое файла ресурсов после его компиляции в сборку.
Необходимо упростить распространение приложения за счет уменьшения количества зависимостей между файлами.
Файлы данных приложения должны быть локализуемыми (см. раздел Обзор локализации и глобализации WPF).
Note
Файлы ресурсов, описанные в этом разделе, отличаются от файлов ресурсов, описанных в разделе ресурсы XAML, а также от внедренных или связанных ресурсов, описанных в разделе управление ресурсами приложения (.NET) .
Настройка файлов ресурсов
В WPF, файл ресурсов — это файл, который включен в проект Microsoft Build Engine (MSBuild) в качестве элемента Resource
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>
Note
В Microsoft Visual Studio, файл ресурсов создается путем добавления файла в проект и присвоения его свойству Build Action
значения Resource
.
При сборке проекта MSBuild компилирует ресурс в сборку.
Использование файлов ресурсов
Чтобы загрузить файл ресурсов, можно вызвать метод GetResourceStream класса Application, передавая ему 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;
Во время вызова методов GetResourceStream вы получаете доступ к Stream. Для преобразования его в тип свойства, с которым можно работать, могут понадобиться дополнительные действия. Вместо этого можно позволить WPF позаботиться об открытии и преобразовании Stream, загрузив файл ресурсов непосредственно в свойство определенного типа.
В следующем примере показано, как загрузить Page непосредственно в Frame (pageFrame
) с помощью кода.
Uri pageUri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
В следующем примере показан эквивалент предыдущего примера, реализованный в коде.
<Frame Name="pageFrame" Source="PageResourceFile.xaml" />
Файлы кода приложения как файлы ресурсов
С помощью pack URI можно ссылаться на определенный набор файлов кода WPF, включая окна, страницы, документы нефиксированного формата и словари ресурсов. Например, можно задать свойство Application.StartupUri с помощью pack URI, ссылающегося на окно или страницу, который вы хотите загрузить при запуске приложения.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="SOOPage.xaml" />
Вы можете это сделать, если файл XAML включен в проект MSBuild в качестве элемента Page
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
Note
В Visual Studio при добавлении нового Window, NavigationWindow, Page, FlowDocument или ResourceDictionary в проект, значением по умолчанию свойства Build Action
для файла разметки будет Page
.
При создании проекта с Page
элементы компилируется, XAML элементы преобразуются в двоичный формат и компилируются в связанную сборку. Следовательно, эти файлы можно использовать таким же образом, как и обычные файлы ресурсов.
Note
Если XAML файл настроен как элемент Resource
и не содержит файл кода, XAML компилируется в сборку необработанным, а не преобразуется в двоичную версию XAML.
Файлы с содержимым
Файл содержимого распространяется как свободный файл вместе с исполняемой сборкой. Несмотря на то, что они не компилируются в сборку, в сборку компилируются метаданные, которые устанавливают связь с каждым файлом содержимого.
Файлы содержимого следует использовать, если приложению требуется определенный набор файлов данных приложения, которые нужно обновлять без перекомпиляции использующей их сборки.
Настройка файлов содержимого
Чтобы добавить файл содержимого в проект, файл данных приложения должен быть включен как элемент Content
. Кроме того, так как файл содержимого не компилируется непосредственно в сборку, необходимо задать элемент метаданных MSBuild CopyToOutputDirectory
, чтобы указать, что файл содержимого копируется в расположение собираемой сборки. Если требуется копировать ресурс в выходную папку сборки при каждом построении проекта, задайте CopyToOutputDirectory
равным Always
. В противном случае убедитесь, обеспечьте копирование только обновленной версии файла установкой значения PreserveNewest
.
Ниже показан файл, настроенный как файл содержимого, который копируется в папку выходных данных построения только при добавлении новой версии ресурса в проект.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Content Include="ContentFile.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...
</Project>
Note
В 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, передавая им 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;
Во время вызова методов GetContentStream вы получаете доступ к Stream. Для преобразования его в тип свойства, которое нужно установить, могут потребоваться дополнительные действия. Вместо этого можно позволить WPF позаботиться об открытии и преобразовании Stream, загрузив файл ресурсов непосредственно в свойство типа.
В следующем примере показано, как загрузить Page непосредственно в Frame (pageFrame
) с помощью кода.
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 (XBAP), запущенным из Интернета или интрасети, и запрашивает только обычный набор разрешений для этих местоположений, свободные файлы могут быть загружены только из узла приложения (исходного места запуска - Site of Origin). Такие файлы называются файлами исходного узла.
Файлы исходного узла являются единственным вариантом для приложений с частичным доверием, хотя и не ограничиваются такими приложениями. Приложениям с полным доверием, возможно, все равно придется загружать файлы данных приложений, о которых они не знают во время построения. Хотя приложения с полным доверием могут использовать схему file:///, вероятнее всего, файлы данных приложения будут установлены в одну папку или вложенную папку со сборкой приложения. В этом случае использовать ссылки на исходный узел проще, чем использовать file:///, так как последнее требует указания полного пути к файлу.
Note
Файлы, исходного узла XBAP не кэшируются на клиентском компьютере, в отличие от файлов содержимого. Следовательно, они загружаются только по специальному запросу. Если приложение обозревателя содержит большие мультимедийные файлы, их настройка в качестве файлов исходного узла означает, что первоначальный запуск приложения выполняется гораздо быстрее, а файлы загружаются только по запросу.
Настройка файлов исходного узла
Если файлы исходного узла не существуют или неизвестны во время компиляции, необходимо использовать традиционные механизмы обеспечения их доступности во время выполнения, включая использование либо программы командной строки XCopy
или Установщик Microsoft Windows.
Если во время компиляции известны файлы, которые должны быть расположены на исходном узле, но все еще требуется избежать явных зависимостей, можно добавить эти файлы в проект MSBuild в качестве элемента None
. Как и для файлов содержимого, необходимо задать атрибут CopyToOutputDirectory
, чтобы указать, что файл исходного узла копируется в расположение относительно сборки построения, указывая значение Always
или PreserveNewest
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
Note
В Visual Studio, файл исходного узла создается путем добавления файла в проект и присвоения его свойству Build Action
значения None
.
Когда проект будет собран, MSBuild скопирует указанные файлы в выходную папку сборки.
Использование файлов исходного узла
Чтобы загрузить файл исходного узла, можно вызвать метод GetRemoteStream класса Application, передавая ему 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;
При вызове метода GetRemoteStream вы получаете объект Stream. Для преобразования его в тип свойства, которое нужно установить, могут потребоваться дополнительные действия. Вместо этого можно позволить WPF позаботиться об открытии и преобразовании Stream, загрузив файл ресурсов непосредственно в свойство типа.
В следующем примере показано, как загрузить Page непосредственно в Frame (pageFrame
) с помощью кода.
Uri pageUri = new Uri("pack://siteoforigin:,,,/SiteOfOriginFile.xaml", UriKind.Absolute);
this.pageFrame.Source = pageUri;
В следующем примере показан эквивалент предыдущего примера, реализованный в разметке.
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
Повторное построение после изменения типа построения
После изменения типа построения файла данных приложения необходимо перестроить все приложение, чтобы обеспечить применение этих изменений. Если просто выполнить построение приложения, изменения не применяются.