Створення власного управління CheckBoxList
Створимо порожній ASP .NET MVC 3 проект і додамо до нього контролерDemoControllerз методом та поданнямIndex:



Після того як мінімальні приготування виконані, переходимо безпосередньо до елемента управління.
Додавання елемента CheckBoxList
Додаємо в корінь проекту папкуCoreз файломControls.csтастатичнимкласомControls, в якому буде розміщена реалізація нашого CheckBoxList'a.

На даний момент, устатичномукласіControlsми вже можемо створювати власні реалізації Html хелперів, тому додамо необхідну для цього кількість коду:
І спробуємо його викликати в нашому уявленніIndex, контролераDemoController.
Примітка: Я навмисно не пишу в тексті статті про збірки, що підключаються, і файли з областю видимості, т.к. сподіваюся, що Ви зможете це зробити без моїх згадок. Єдине, що варто вказати, так це додавання рядка до файлу /Views/web.config, де MVC3Controls_H.Core, це розташування Вашого статичного класу з CheckBoxList'ом.
Для виклику нашого елемента, додаємо вIndex.cshtml(якщо Ви вказали Razor Engine при додаванні нового подання) наступний рядок:
і вкажемо у файліGlobal.asax, який знаходиться в корені проекту, що за замовчуванням потрібно викликати контролерDemo, методIndex:
Якщо всі дії були зроблені правильно, Ви побачите сторінку наступного змісту:
Чудово. Тепер переходимо до реалізації структури нашого CheckBoxList'a.
Реалізація структури CheckBoxList
Насамперед, додамо налаштування його відображення у файлControls.cs. В нашомуу випадку, це будуть 3 об'єкти типуenum:
І класCheckBoxList_Settings, в якому ми і будемо їх передавати у виклик нашого елемента управління:
Як налаштування за замовчуванням ми виберемо каркас-таблиця, напрямок виведення-по горизонталі та відображення у вигляді п'яти колонок. Властивістьcbl_Nameми розглянемо пізніше. Змінюємо конструктор нашого CheckBoxList'а, щоб він приймав колекцію типу IDictionary та екземпляр класу налаштувань:
Ми прийшли до того, що в поданні нам тепер потрібно не лише викликати наш елемент, але й передати йому 2 параметри, для цього додамо вIndexметод нашого контролера колекцію даних:
І надамо нашому уявленню ці дані як модель:
У коді нашого подання вказуємо, що моделлю для нього є тип даних Dictionary та викликаємо наш CheckBoxList:
Запускаємо проект і бачимо той самий звичний для нас запис:
Аналіз поточної структури програми
Додавання моделі подання
Так як наша модель уявлення служить не тільки для того, щоб в ній передавати дані, але і щоб їх отримувати, то нам потрібно крім колекції, що передається, так само додати і масив обраних елементів. Додамо в папкуModelsпапкуViewModels, потім додамо вViewModelsфайлViewModel_Index.csяк показано нижче:

та код нашої моделі представлення:
Indexметод нашогоDemoController'a зміниться так:
Так як ми змінили модель, що передається в контролері, то це так само необхідно зробити і в пов'язаному з ним поданні:
Таким чином, якщо Вам знадобиться окрім колекції даних для нашого елементу управління, передати щось ще на сторінку, то Ви зможете зробити це,просто змінивши модель уявлення/Models/ViewModels/ViewModels_Index.cs(доповнивши її новими властивостями) і додавши їх ініціалізацію у методі контролера.
Інкапсуляція виклику нашого CheckBoxList
У своїй першій статті я вже застосовував подібну схему виклику розширюючого методу, проте для інших цілей. У поточному ж проекті, щоб винести виклик нашого CheckBoxList'a в Partial View ми додамо в папку/ViewsпапкуPartial, до неї папкуControls, а в папкуControlsнове часткове уявленняCheckBoxList.cshtml:

Тепер структура нашої програми виглядає так:

Змінюємо нашеIndexуявлення, викликаючи замість CheckBoxList'а наше Partial View:
Додавання моделі даних для CheckBoxList
Так як ми плануємо перенести виклик нашого елемента управління в наш Partial View, то туди ж потрібно передавати дані для нього, - отже, нам необхідно додати для нього модель даних. У папціModelsстворимо нову папкуCheckBoxList, до неї додамо класCheckBoxList_Model.cs:
Змінимо в нашомуIndexподанні виклик Partial View, передаючи як дані додану модель:
і визначимо цю модель, як модель для нашого Partial View в/Views/Partial/Controls/CheckBoxList.cshtml, викликаючи і передаючи значення наш елемент управління:
На цьому зі структурою програми покінчено. Розглянемо основні її моменти:

Хороша новина полягає в тому, що ми закінчили зі структурою нашого додатка, а погана - ми ще практично нічого не написали про сам наш CheckBoxList.
Реалізація CheckBoxList
Почнемо з того, що опишемо загальний алгоритмпобудови нашого елемента: 1. Вибір HTML тега (table, div), що обрамляє, на основі параметраcbl_Layout. 2. Визначення кількості ітерацій по колекції на основі параметраcbl_RepeatColumnsі кількості записів в колекції. 3. Формування умови вибірки елементів із колекції з урахуванням порядкового номера поточної итерации: 3.1. Якщо висновок здійснюється по горизонталі, а кількість колонок = 4, то перший рядок повинен складатися з перших 4-х елементів колекції, що йдуть по порядку, другий з наступних 4х і т.д.:
3.2. Якщо висновок здійснюється по вертикалі, кількість колонок = 4 а всього елементів 24, то перший рядок повинен складатися (!) з кожного шостого елемента колекції, другий з № ітерації + 6 і т.д.:
3.3. Не варто забувати при обчисленні кіл-ва ітерацій (кількість елементів / у колонок) про залишок від розподілу! = 0. У цьому випадку нам знадобиться зайва ітерація для виведення всієї колекції.
4. Формування рядка з відповідних під умову вибірки кожної ітерації, залежно від обрамляющего тега (div, table): 4.1. Для div це будуть лише перенесення наприкінці рядка. 4.2. Для table це: 4.2.1.
Так як основною думкою статті не є код і алгоритми, то я наведу тільки частину функцій, - решту Ви зможете побачити завантаживши проект наприкінці статті, зупинившись хіба що докладніше на формуванні розмітки CheckBox'a:
Формування HTML розмітки CheckBox'a та Model Binding
Загалом, це найпростіший код, якому передається елемент колекції та налаштування нашого елемента керування. Мабуть головним у цьомуКод буде те, що атрибуту name присвоюється ім'я всього нашого CheckBoxList'a. Це зроблено для того, щоб надалі, при отриманні даних на стороні сервера в нашому методіIndexконтролераDemoControllerми змогли отримати вибрані значення у вигляді сформованого масиву, трохи пізніше я покажу це на прикладі.
Формування HTML розмітки Label'a
Обчислення кіл-ва ітерацій:
Умова вибірки для кожної ітерації:
де i – номер ітерації. При виведенні по горизонталі ми беремо елементи, індекси яких при розподілі на кількість колонок == i:
При виведенні по вертикалі ми беремо елементи, залишок від розподілу індексу якого і поточної ітерації на кількість ітерацій == 0:
Перевірка працездатності
Давайте на прикладі 3х CheckBoxList'ов подивимося, що ж у результаті ми отримали:

Для того, щоб отримати вибрані значення, нам потрібно буде в модель нашого представленняViewModel_Indexдодати 3 масиви з іменами, які ми передаємо для наших CheckBoxList'ів:
а також додати метод контролераIndex, який обробляє запити:
Поставивши точку зупинки, подивимося на результат:

Якщо ж Вам абсолютно байдужі дублювання коду, моделі уявлень та супровід, то Ви так само просто можете викликати безпосередньо сам CheckBoxList у поданні та отримати вибрані значення на сервері прямо в масиві (проте варто не забувати про те, що ім'я CheckBoxList'a і параметр, що приймається) на сервері повинні бути однакові):



Що ж, тепер, коли ми повністю закінчили те, що планували, залишилося останнє. Розглянути можливість розширення нашого елемента управління новими властивостями з прикладуobjecthtmlAttributes.
Розширюємо CheckBoxList
Для того, щоб передати нову властивість код нашого елемента, ми повинні пройтися від конструктора, до початкового виклику (або навпаки, як кому більше подобається). Все починається з нашого конструктора вControls.cs- додаємо новий параметр object htmlAttributes:
Виклик нашого конструктора здійснюється у Partial View з ім'ямCheckBoxList.cshtml. Додаємо нову властивість для моделі CheckBoxList'a:
І передамо його під час виклику в нашому Partial View:
Залишилося додати саму ініціалізацію властивості в представленніIndexі доповнити код нашого елемента:
Код вибору каркасу (table, div):
Як можна побачити нижче, все працює:

Висновок
Як висновок, хотілося б зрозуміти, що ж ми все-таки зробили:
- Розглянули можливість створення, використання та розширення власного елемента керування на базі Html хелперів ASP .NET MVC;
- Створили каркас проекту для подальших розробок елементів керування;
- Реалізували структуру веб-додатка з розподілом обов'язків кожної функціональної одиниці;
- Дізналися про сайт, з яким є чим позмагатися при написанні власних елементів управління.
Список матеріалів
Хардкорна конфа за С++. Ми запрошуємо лише профі.