Двоичные ресурсы

92

Приложение Silverlight фактически является набором файлов, упакованных в одном файле ZIP с расширением .xap. Файл XAP содержит манифест (список файлов используемых в проекте), сборку приложения и ресурсы.

Ресурс XAP - это отдельный файл, который можно сделать доступным в скомпилированном приложении. В ресурсы обычно включают изображения, аудио- и видеофайлы, которые нужно отобразить в пользовательском интерфейсе приложения.

Ресурсы можно хранить в разных местах, поэтому иногда их чрезмерно усложняют, хотя в этом нет необходимости. Ниже перечислены места, в которых можно хранить ресурсы:

Сборка приложения

Файл ресурса внедряется в скомпилированный DLL-файл проекта, например SilverlightApplication.dll. В рабочей среде Visual Studio этот способ сохранения используется по умолчанию.

Пакет приложения

Файл ресурса сохраняется в архиве XAP наряду со сборкой приложения. Его так же легко развернуть, но, по сравнению с предыдущим способом, им легче управлять, потому что в пакете XAP его можно заменить или отредактировать, не компилируя приложение.

Исходный сайт.

Файл ресурса хранится на сайте вместе с файлом XAP. В этом случае развертывание существенно усложняется, потому что, кроме файла XAP, нужно предоставить файл ресурсов. Однако разработчик получает возможность использовать ресурс другими способами, например, в качестве изображения, отображаемого на обычной веб-странице. Ресурс видео можно сделать доступным для потокового воспроизведения. Кроме того, при использовании данного способа существенно уменьшается размер исходного загружаемого файла XAP, что очень важно, если ресурс большой.

Возможны и другие способы хранения ресурсов. Например, ресурс можно хранить в других сборках, используемых приложением . Этот способ облегчает управление содержимым, используемым в разных приложениях Silverlight. Однако, прежде чем обсудить этот способ, необходимо рассмотреть более популярные варианты, перечисленные выше. В следующих разделах подробно обсуждается каждый способ размещения ресурсов.

Не путайте двоичные ресурсы с ресурсами XAML. Ресурс XAML - это объект, объявленный в разметке, а двоичный ресурс — это невыполняемый файл, вставленный в сборку или файл XAP во время компиляции проекта.

Включение ресурса в сборку приложения

Это стандартный подход, аналогичный используемому в приложениях .NET других типов (например, в приложениях WPF). Например, если нужно вывести изображение в элементе Image, добавьте файл изображения в проект. По умолчанию программа Visual Studio присвоит свойству Build Action файла изображения значение Resource:

Ресурс, внедренный в сборку приложения

Чтобы изменить значение Build Action любого файла, щелкните в поле свойства в окне Properties (Свойства). Когда появится стрелка раскрывающегося списка, щелкните на ней и установите нужное значение.

Не путайте значения Resource и Embedded Resource свойства Build Action. Оба они внедряют ресурс в сборку как блок двоичных данных, однако Silverlight не поддерживает значение Embedded Resource. Оно принадлежит программе Visual Studio, а не Silverlight. При его установке сослаться на файл с помощью адреса URI будет невозможно.

При компиляции приложения ресурс внедряется в сборку проекта, которая помещается в файл XAP.

Пользователю тяжело извлечь файл ресурса, внедренного в сборку приложения. Однако это все же возможно. Для этого пользователь должен загрузить файл XAP на локальный диск, разархивировать его и распаковать DLL-файл с помощью какого-либо декомпилятора.

Использовать внедренный ресурс легко, потому что в Silverlight для обращения к нему можно применить адрес URI. При использовании относительного адреса URI с элементом Image (для изображения) или MediaElement (для медийных файлов) надстройка Silverlight ищет в сборке ресурс, имеющий заданное имя. Если файл ресурса расположен в корневой папке приложения, достаточно указать его имя:

<Image Source="myimage.png" Stretch="None"/>

Использование вложенных папок

Для группирования файлов ресурсов, внедренных в проект, можно использовать вложенные папки. Например, файл myimage.png можно поместить во вложенную папку Images:

Ресурс во вложенной папке

Имя вложенной папки нужно включить в URI-адрес:

<Image Source="Images/myimage.png" Stretch="None"/>

Программное извлечение ресурса

Использование ресурсов облегчается тем, что платформа Silverlight поддерживает в элементах Image и MediaElement стандарты URI. Однако в некоторых ситуациях возникает необходимость манипулирования ресурсом в коде до его передачи элементу, а иногда элемент вообще не используется. Например, в ресурсе могут храниться текстовые или двоичные данные, и код должен извлечь и обработать их.

Эта задача решается с помощью метода Application.GetResourceStream(), предназначенного для извлечения данных из указанного ресурса. Ресурс задается с помощью адреса URI в следующем формате:

/имя_сборки;component/имя_файла_ресурса

Предположим, в проекте SilverlightApplication определен ресурс ProductList.bin. Извлечь его можно с помощью следующего кода:

using System.Windows.Resources;
   ...
   
    StreamResourceInfo sri = Application.GetResourceStream(
         new Uri("SilverlightApplication;" +
              "component/ProductList.bin", UriKind.Relative));

Метод GetResourceStream(), несмотря на его название, не извлекает поток. Вместо этого он получает объект типа StreamResourceInfo. Этот объект является оболочкой свойства Stream представляющего поток чтения, и свойства ContentType, определяющего тип MIME. Ниже приведен код, создающий объект чтения потока типа BinaryReader:

System.IO.BinaryReader reader =
     new System.IO.BinaryReader(sri.Stream);

Методы объекта типа BinaryReader можно использовать для извлечения из файла произвольной части данных. Этот же способ используется в объектах StreamReader (для чтения текстовых данных) и XmlReader (для чтения данных XML).

Включение ресурса в пакет приложения

Еще один вариант хранения ресурса состоит в помещении его в файл XAP. в котором хранится сборка приложения. Для этого нужно добавить файл ресурса в проект и присвоить свойству Build Action значение Content. При этом используются те же адреса URI, что и при хранении ресурса в сборке приложения (предыдущий вариант). Нужно лишь поместить перед адресом косую черту:

<Image Source="/myimage.png" Stretch="None"/>

Аналогично предыдущему варианту, ресурс можно хранить во вложенной папке:

<Image Source="/Images/myimage.png" Stretch="None"/>

Косая черта обозначает корневую папку архива XAP. Присвоив файлу XAP расширение .zip, можно разархивировать его и убедиться в том, что в нем есть файл ресурса:

Файл ресурса в архиве XAP

При размещении ресурса в файле XAP развертывание приложения выполняется так же легко, как и при внедрении в сборку, однако гибкость приложения повышается. Приложив дополнительные усилия, можно манипулировать файлом ресурса в архиве XAP (например, обновлять графические файлы), не перекомпилируя приложение. Более того, если в файле XAP хранятся несколько библиотечных сборок классов, все они могут пользоваться файлами ресурсов, хранящимися в файле XAP (этот способ используется редко, но он возможен). В целом внедрение ресурса в сборку и размещение в пакете приложения — приблизительно равнозначные методы.

Размещение ресурсов в Интернете

Последний вариант: файлы ресурсов можно полностью удалить из приложении и сделать их доступными в Интернете. Приложение будет автоматически загружать их по мере необходимости. Благодаря тому, что Silverlight поддерживает адреса URI, для реализации этого метода нет необходимости писать дополнительный код; надстройка Silverlight сама загрузит нужные ресурсы.

Проще всего разместить файлы ресурсов на том же сайте, что и сборку Silverlight. Если применяется тестовый сайт ASP.NET, добавьте файл ресурса в папку ClientBin, в которой находится файл XAP. При использовании тестовой страницы HTML добавьте файл ресурса в проект Silverlight и явно укажите программе Visual Studio, что с ним нужно делать. Выделите файл ресурса и присвойте свойству Build Action значение None, а свойству Copy to Output Directory — значение Copy Always.

Для обращения к ресурсу, размещенному в Интернете, используется тот же адрес URI, что и при размещении в пакете приложения. Ниже приведен пример относительного URI:

<Image Source="/myimage.png" Stretch="None"/>

Выполняя поиск ресурса, заданного таким образом, надстройка Silverlight сначала просматривает файл XAP, а затем — папку, в которой расположен файл XAP. Следовательно, можно легко переключаться между разными методами размещения ресурса: в файле XAP и в Интернете. Не нужно ни менять что-либо в приложении, ни перекомпилировать его. Достаточно удалить или добавить файл ресурса в файл XAP или в папку приложения.

Ресурс не обязательно размещать на том же сайте, что и файл XAP, хотя чаще всего так и делают. При использовании абсолютного адреса URI ресурс можно извлечь с любого сайта:

<Image Source="http://www.somesite.com/Images/myimage.png" Stretch="None"/>

При тестировании приложения, в котором есть файлы изображений с абсолютными адресами, возникает небольшая проблема: элемент Image не может обращаться к другим схемам. Это означает, что при выполнении приложения Silverlight непосредственно с жесткого диска с помощью простой тестовой HTML-страницы оно не сможет загрузить изображение из Интернета. Для решения проблемы добавьте в проект тестовый сайт ASP.NET.

Ресурсы, размещенные в Интернете, интерпретируются приложением немного иначе, чем размещенные в приложении. Они не являются частью файла XAP, поэтому не сжаты. Если используется большой, легко сжимаемый файл (например, файл XML), размещенный в Интернете ресурс будет намного дольше загружаться (по крайней мере, для части пользователей).

Еще более важен тот факт, что ресурсы, размещенные в Интернете, загружаются по требованию, когда приложение обращается к ним. Поэтому при большом количестве небольших ресурсов (особенно несжимаемых) предпочтительнее размещение в Интернете. В этом случае оно обеспечит малое время начальной загрузки приложения при небольших задержках на загрузку отдельных ресурсов.

Очевидный недостаток всех трех указанных способов хранения ресурсов состоит в том, что в них используются фиксированные, неизменяемые данные. Приложение не может изменить файл ресурса и сохранить измененную версию в сборке, файле XAP или Интернете (теоретически можно было бы разрешить выгрузку измененных ресурсов на сайт, но это создало бы бреши в системе безопасности). Если все же нужно изменять ресурсы, наилучшее решение состоит в их сохранении в изолированном хранилище на жестком диске или на сервере с помощью веб-службы.

Неудачная загрузка ресурса

Если в приложении применяется ресурс, размещенный в Интернете, всегда существует возможность того, что он окажется недоступным. Поэтому элементы, ожидающие ресурсы, обычно предоставляют события, извещающие о том, что загрузка не может быть успешно завершена. Например, элемент Image предоставляет событие ImageFailed, а элемент MediaElement — событие MediaFailed.

Неудачная загрузка ресурса не является критической ошибкой. Если элемент Image не может загрузить рисунок, на экране всего лишь рисуется пустая рамка. Разработчик может предусмотреть в приложении какую-либо реакцию на неудачную загрузку ресурса.

Загрузка ресурса с помощью класса WebClient

К ресурсу, размещенному в Интернете, нельзя получить доступ с помощью рассмотренного выше удобного метода Application.GetResourceStream(). Поэтому, если нужно использовать данные ресурса, размещенного в Интернете, причем для ресурса нет элемента, в котором можно задать адрес URI, вам придется проделать дополнительную работу.

В этой ситуации для загрузки ресурса можно применить класс System.Net.WebClient, предоставляющий три основных метода. Наиболее полезен метод OpenReadAsync(). Он загружает файл как набор двоичных данных, которые затем предоставляются приложению в потоке. Метод DownloadStringAsync() загружает содержимое ресурса в одну строку. И наконец, метод CancelAsync() останавливает текущую загрузку.

Методы класса WebClient работают асинхронно. Событие DownloadProgressChanged можно использовать во время загрузки для выяснения количества полученных байтов. Момент завершения загрузки можно поймать с помощью события OpenReadCompleted или DownloadStringCompleted (в зависимости от метода загрузки). Когда загрузка завершена, приложение имеет возможность прочесть содержимое ресурса в потоке или строке.

Методам класса WebClient присущи три существенных ограничения:

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