Своя піктограма

Це, звичайно, справа смаку, але приємніше дивитися на власну
піктограму на панелі інструментів (Toolbox), ніж на шестірню (нехай
навіть красиво намальовану). Як це зробити? Дуже просто – слідуючи
документації ([1]), задати класу атрибут ToolboxBitmap. У цього
атрибуту є три варіанти ініціалізації, причому перший, що використовує
шлях до файлу, використовувати не слід (причина банальна, але вагома –
файл з піктограмою, в цьому випадку, не буде частиною збірки).

Все було б дійсно просто, якщо б не один нюанс. Розповідаю
історію кількох невеселих годин мого життя. Створив я проект (Class
Library), поміняв трохи назва файлу, простору імен і самого
класу. Після чого успадкував клас від ListView (System.Windows.Forms),
намалював піктограму і додав атрибут ToolboxBitmap. Вийшло
приблизно наступне:

 

namespace Windows.Controls
{
[ToolboxBitmap(typeof(CListView), "ListView.ico")]
public class CListView : ListView

Скомпілював я збірку, додав компонент в панель інструментів і
дуже здивувався, побачивши до болю знайому шестірню. Витративши не один
годину на спроби домогтися потрібного результату, я почав схилятися до думки,
що помилка насправді в ДНК. Випивши чаю і трохи заспокоївшись, я
вирішив подивитися уважніше на ресурси в моїй збірці (це легко
зробити за допомогою методу Assembly.GetManifestResourceNames або утиліти
ILDasm). Результат виправдав очікування – виявилося, що відповідний
ресурс називається "Controls.ListView.ico", а студія, звичайно ж, шукала
"Windows.Controls.ListView.ico". Після цього проблема вирішилася за пару
хвилин, установкою властивості проекту "Default Namespace".

Послідовність дій при додаванні своєї піктограми до
компоненту виглядає так:

  1. Додати іконку в проект як "embedded resource".
  2. Поставити класу атрибут "ToolboxBitmap".
  3. Упевнитися, що властивість проекту "Default Namespace"
    відповідає простору імен шуканого класу.
  4. Перекомпілювати проект.

Відзначу також, що, помістивши піктограми в окрему папку проекту, потрібно
додати до назви файлу ім'я папки через крапку (наприклад
"icons.ListView.ico").

 

Створення редактора типів (TypeEditor)

Безсумнівно, без візуального редагування компонентів написання
додатків істотно сповільнилося б. В. NET є набір стандартних
редакторів типів, який, проте, в деяких ситуаціях потребує
розширення. Гарним прикладом такої ситуації є реалізація в
власному елементі управління властивості DataSource. У документації
([1]) описано створення свого редактора типів, але деякі моменти
висвітлено недостатньо докладно. Спробую заповнити цю прогалину.

Перш за все, слід написати "Конвертор типів" (похідний клас
від TypeConverter), для того, щоб значення властивості відображалося
належним чином. Якщо не ускладнювати собі життя, то можна реалізувати
лише перетворення потрібних типів (DataTable, ..) в рядок. Зазвичай для
цього використовується властивість Component.Site.Name.

Потім, потрібно успадкувати свій клас від UITypeEditor і, залежно
від потрібної функціональності при редагуванні властивості, у методі
GetEditStyle повернути відповідний UITypeEditorEditStyle. Основний
метод редактора типів – EditValue – викликається при спробі користувача
(Редактора типів) змінити значення властивості. У ньому, за допомогою сервісу
IWindowsFormsEditorService, можна показати випадаючий список можливих
значень властивостей або форму. Я особисто віддаю перевагу список, що випадає,
оскільки працювати з ним швидше. Відзначу також, що
IWindowsFormsEditorService дозволяє показувати не тільки стандартний
ListBox, але і будь-який інший (у тому числі для користувача) елемент
управління. Для наповнення списку зазвичай достатньо перерахувати
компоненти на формі і додати в список підходящі (наприклад, в
залежно від їх типу). Зробити це можна за допомогою параметра
"ITypeDescriptorContext context":

 

foreach( IComponent component in context.Container.Components )
{
	…
}

Після завершення реалізації редактора типів, потрібно задати у властивості
відповідні атрибути (TypeConverter, Editor і, при бажанні,
Category, DefaultValue, Description і т.п.):

 

[Category("Data"),
TypeConverter (typeof (Windows.Controls.CDataSourceValueConverter)),
Editor(typeof(Windows.Controls.CDataSourceTypeEditor),
typeof(UITypeEditor)),
DefaultValue(null),
Description ("Джерело даних.")]
public object DataSource

Редагування колекцій

Для редагування своїх колекцій писати свій редактор типів
необов'язково. Стандартний редактор (CollectionEditor) надає
цілком прийнятну функціональність. Він визначає тип містяться в
колекції об'єктів за допомогою властивості Item (наприклад, індексатора в
C #). Все що потрібно – це написати клас, який реалізує інтерфейс
ICollection (можна використовувати клас
"System.Collections.CollectionBase"). Потім для властивості задати атрибут
ReadOnly (true), оскільки властивість, по ідеї, не повинно змінюватися і
DesignerSerializationVisibility (DesignerSerializationVisibility.Content)
для правильної серіалізациі колекції.

Реєстрація компонента для вкладки ". NET Framework Components"

При додаванні компонента в панель інструментів можна піти двома
шляхами: вибрати компонент зі списку або вибрати файл компоненту. При
частому використанні одних і тих же рідко редагованих компонентів
простіше використовувати перший варіант. Для цього потрібно шлях до папки,
містить збірку (збірки) з компонентами, помістити в ключ реєстру
"HKEY_LOCAL_MACHINESOFTWAREMicrosoft.NETFrameworkAssemblyFolders".
Після цього – перезапустити студію.

Використання Win32 API

Ні для кого не секрет, що керуючі елементи в. NET надають
доступ далеко не до всіх своїх властивостях. Координати заголовка стовпця в
ListView, наприклад, одержати вкрай важко. З іншого боку,
програмуючи з використанням Win32 API, зробити це простіше простого –
отримати вікно заголовка (подія LVM_GETHEADER) і взяти у нього
координати заголовка за індексом (подія HDM_GETITEMRECT). Користуватися
Win32 API нескладно ([2]), потрібно лише оголосити потрібні функції за допомогою
атрибуту DllImport:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, 
int msg, int wParam, int lParam);

Деяку проблему представляє лише робота зі структурами (атрибут
StructLayout). Прочитавши цей розділ, Ви можете подумати, що я закликаю
користуватися Win32 API – повірте, це не так. Навпаки – я сам намагаюся
цього уникнути. Основний недолік використання Win32 API –
обмеження кола операційних систем, на яких може бути запроваджено
рішення. Більш того, зустрічаються ситуації, коли одні й ті ж
API-функції ведуть себе по-різному на різних Windows-платформах. Але якщо
Ваша програма має працювати тільки на одній конкретній операційної
системі, використання Win32 API цілком припустимо (за відсутності
аналогів в. NET).

Спадкування керуючих елементів

Спадкування керуючих елементів – тема надто широка для однієї
статті, тому висловлю лише деякі міркування з цього приводу.
Питання про те, коли і як використовувати успадкування, досить добре
висвітлений у документації ([3], [4]). Від себе додам, що успадкування
елементів управління вельми корисно, коли є свій каркас додатка,
вирішальний приватні задачі і не претендує на універсальність. У цьому
випадку можна орієнтувати елементи управління на цей каркас, що
допоможе надалі прискорити розробку програм.

І ще одне зауваження, з приводу візуального редагування. Іноді
необхідно трохи змінити функціональність деякого властивості
базового елементу управління, яке не оголошено як virtual.
Наприклад, хочеться обмежити можливі значення цієї властивості. Вирішити
таке завдання можна за допомогою модифікатора new. Звичайно, при цьому
залишиться можливість доступу до цієї властивості ззовні (з допомогою
приведення типу до базового класу). Але, з іншого боку, при візуальному
проектуванні цього не станеться, а необхідність приведення типу
керуючого елемента до базового елементу найчастіше вельми сумнівна.

 

Висновок

Створення компонент, як і програмування в цілому – процес творчий
і кожен вирішує сам як саме це робити. Сподіваюся, що ця стаття
допоможе Вам на перших етапах розробки.

 

Література (MSDN)

  1. Control Authoring for Windows Forms.
  2. Consuming Unmanaged DLL Functions.
  3. Authoring Controls for Windows Forms.
  4. Control Type Recommendations.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*