Керовані (managed) ресурси в виконуваних файлах

буде створено файл MyStrings.resources, який можна включити в проект.

Додавання ресурсів в VS.NET

У певному сенсі найпростішим видом ресурсу є файл як такої, як одиниця зберігання, причому тип файлу не грає ролі. Це може бути файл з картинкою, з якоюсь закодованою інформацією, і так далі ... Додавання вмісту файлу до складу ресурсів є, можливо, найпростішим способом додавання ресурсів в виконуваний файл. Подивимося, як це можна зробити.

Припустимо, на вінчестері вже приготований файл з ім'ям Bitmap1.bmp, що містить якусь картинку (ім'я файлу і характер інформації в ньому можуть бути будь-якими). Щоб додати вміст файлу Bitmap1.bmp в виконуваний файл в якості ресурсу, необхідно зробити наступні дії:

У вікні Solution Explorer'а виділити елемент, відповідний проекту, що розробляється, після чого натиснути правою кнопкою миші.

У який з'явився popup-меню вибрати елемент «Add», після чого в черговому popup-меню вибрати елемент «Add existing item».

У діалоговому вікні вибрати файл, який повинен бути доданий в проект.

Після виконання всіх цих дій файл з'явиться в дереві проекту (див. Малюнок 1):

У контекстному меню доданого файлу вибрати пункт «Properties», що, в свою чергу, призведе до появи вікна «Properties», в якому можна буде відкоригувати властивості файлу.

Вибрати в властивості «Build Action» значення «Embedded Resource» (див. Рисунок 2):

Після цих дій і компіляції вміст файлу Bitmap1.bmp буде включений до складу ресурсів. Таким способом до складу ресурсів може бути включено будь-(в розумних межах, звичайно) кількість будь-яких файлів. Зрозуміло, що при цьому ніяких дій з вмістом файла проводитися не буде, в розділі керованих ресурсів з'явиться копія вмісту файлу.

Як вже говорилося, до складу ресурсів можуть бути додані і ресурси формату .resources. Для цього необхідно виконати наступні дії:

В результаті цих дій Visual Studio створить XML-файл, частина вмісту якого можна побачити на малюнку 4.

Цей файл буде мати розширення .resx, і при компіляції проекту його вміст буде перетворено в .resources і включено в виконуваний файл.

На жаль, за допомогою grid'а (див. Малюнок 3) Visual Studio .NET додати в .resx дані не примітивних типів, наприклад, картинку, практично неможливо, це може бути зроблено тільки за допомогою сериализации даних в ресурси.

Особливо необхідно сказати про файлах .resx, що містять дані про форми, створених Form Designer'ом. У них, природно, також зберігаються ресурси. Але! Ці файли генеруються автоматично. Тому в загальному випадку при додаванні в ці файли якихось даних при перекомпіляції проекту ці дані будуть втрачені.

Використання ресурсів в додатку

Зрозуміло, що ресурси створюються для того, щоб згодом отримати від них дані. Доступ до ресурсів здійснюється за допомогою методу GetManifestResourceStream. Скажімо, для того, щоб звернутися до раніше доданому в ресурси Bitmap1.bmp, можна використовувати наступну послідовність операторів:

Очевидно, що формат .resource створювався з розрахунком на те, що дані з нього будуть зчитуватися поелементно, причому пошук окремого ресурсу всередині цього формату буде проводитися по імені цього ресурсу. Для доступу до ресурсів можна використовувати методи класу ResourceManager. Два його основні методи, GetString і GetObject, призначені для завантаження з ресурсів рядків і об'єктів відповідно. Нижче наведено приклад використання об'єкта класу ResourceManager для завантаження рядки, раніше доданої в .resources:

Цей метод повертає не просто набір байтів, а екземпляр класу System.String. Метод GetObject знаходить ресурс-елемент із зазначеним ім'ям, створює нову реалізацію об'єкта і завантажує в нього (за допомогою BinaryFormatter'а) стан об'єкта. Таким чином, можна сказати, що методи ResourceManager завантажують об'єкти з ресурсів за деякими логічним іменам. Як говорилося раніше, в першу чергу цей механізм був призначений для завантаження стану компонентів і їх вмісту в дизайнерів, таких, як Windows Forms і ASP.NET. За замовчуванням дизайнери намагаються серіалізовать стан компонентів в код, але бувають випадки, коли сериализация в код неможлива. Наприклад, важко (і нерозумно) серіалізовать в код вміст картинок. До того ж для того, щоб дизайнер міг повністю серіалізовать в код все властивості компонента, розробник компонента повинен зробити деякі дії (реалізувати TypeConverter, що перетворює екземпляр об'єкта в спеціальний клас-опис примірника - InstanceDescriptor). Якщо такого немає, і Серіалізуемое клас не є компонентом, дизайнер спробує серіалізовать стан екземпляра BinaryFormatter'ом. Якщо це вдасться, він запише цей стан в .resx-файл, а в код підставить виклик методу ResourceManager.GetObject. При цьому ресурсу буде дано ім'я виду ІмяКомпонента.ІмяСвойства. Наприклад, компонент pictureBox1 (типу System.Windows.Forms.PictureBox) має властивість Image типу System.Drawing.Image. Цей тип не підтримує сериализацию в код, так йому це не особливо й потрібно, так як основне його вміст - це картинка. Тому дизайнери серіалізуются об'єкти такого типу в ресурси (.resx-файли). Після компіляції .resx-файли перетворюються в ресурси формату .resources з іменами, відповідними іменами форм виду ПространствоІменПрінятоеПоУмолчанію.ІмяФорми.resources. При цьому в самому початку методу InitializeComponent відповідної форми додається код, не започатковано екземпляр ResourceManager:

а ділянку коду ініціалізації компонента (в нашому випадку pictureBox1) додається в код завантаження об'єкта з ресурсу: