Извлечение ресурсов

59

Очевидно, что в добавлении ресурсов нет ничего сложного, но как их на самом деле использовать? Здесь существует несколько подходов. Самый простой — извлечь объект StreamResourceInfo, упаковывающий данные, и затем решить, что с ним делать. Сделать это можно в коде с помощью метода Application.GetResourceStream(). Например, ниже показан код, извлекающий объект StreamResourcelnfo для изображения:

StreamResourceInfo sr = 
     Application.GetResourceStream(new Uri("red_heart.png", UriKind.Relative));

Имея объект StreamResourceInfo, можно получить два фрагмента информации. Свойство ContentType возвращает строку, описывающую тип данных — в настоящем примере это image/jpg. Свойство Stream возвращает объект UnmanagedMemoryStream, который можно использовать для считывания данных по одному байту за раз.

Метод GetResourceStream() на самом деле представляет собой всего лишь вспомогательный метод, который упаковывает классы ResourceManager и ResourceSet. Эти классы являются главной частью системы ресурсов .NET Framework и существуют, начиная с версии 1.0. Без метода GetResourceStream() нужно было бы специально получать доступ к ресурсному потоку AssemblyName.g.resources (в котором хранятся все ресурсы WPF) и осуществлять поиск требуемого объекта.

Классы, поддерживающие ресурсы

Даже с помощью метода GetResourceStream() все равно вряд ли захочется возиться с извлечением ресурсов напрямую. Проблема в том, что при таком подходе получается объект UnmanagedMemoryStream относительно низкого уровня, от которого мало толку. Наверняка понадобится преобразовать данные во что-нибудь более значимое вроде высокоуровневого объекта со свойствами и методами.

WPF предлагает несколько классов, которые умеют работать с ресурсами. Вместо того чтобы вынуждать извлекать ресурсы (что засоряет код и делает его небезопасным в отношении типов), они принимают имя ресурса, который необходимо использовать. Например, если необходимо отобразить изображение Blue hills.jpg, можно воспользоваться такой разметкой:

<Image Source="Images/Blue hills.jpg"></Image>

Обратите внимание, что обратная косая черта становится обычной косой чертой, поскольку именно такое соглашение WPF использует для URI-идентификаторов. (В принципе рабочим является и тот и другой вариант, но все-таки для согласованности рекомендуется применять обычную косую черту.)

То же самое можно сделать и в коде. В случае элемента Image потребуется просто установить для свойства Source в качестве значения объект BitmapImage, указывающий на местонахождение изображения, которое требуется отобразить, в виде URI. Указать на полностью уточненный путь к файлу можно следующим образом:

img.Source = new BitmapImage(new Uri(@"d:\Photo\Backgrounds\arch.jpg"));

Но в случае применения относительного URI можно извлечь из сборки другой ресурс и передать его изображению безо всякого объекта UnmanagedMemoryStream:

img.Source = new BitmapImage (new Uri ("images/winter.jpg", UriKind.Relative));

Такой подход приведет к созданию URI, состоящего из базового URI приложения с добавленной в конце конструкцией images/winter.jpg. В большинстве случаев думать о таком синтаксисе URI не нужно — если придерживаться относительных URI, все будет работать без сучка и задоринки. Однако в некоторых случаях важно разбираться в системе URI более детально, особенно, когда требуется доступ к ресурсу, находящемуся в другой сборке.

Пройди тесты
Лучший чат для C# программистов