Пользовательские элементы управления ASP.NET - Композиты

Резюме

Привет всем,
хорошо, дальше мои приключения с настраиваемым управлением ...

Таким образом, я узнал о трех основных «классах» настраиваемых элементов управления. Пожалуйста, не стесняйтесь поправлять меня, если что-то не так!

  1. UserControls - наследуются от UserControl и содержатся в файле ASCX . Они довольно ограничены в том, что они могут делать, но представляют собой быстрый и легкий способ получить некоторую универсальность пользовательского интерфейса с поддержкой дизайнера.
  2. Настраиваемые составные элементы управления - это элементы управления, которые наследуются от WebControl, где вы добавляете уже существующие элементы управления в элемент управления в методе CreateChildControls . Это обеспечивает большую гибкость, но отсутствие поддержки дизайнера без дополнительного кодирования. Однако они очень портативны, поскольку могут быть скомпилированы в DLL.
  3. Настраиваемые визуализированные элементы управления - аналогично настраиваемым составным элементам управления, они добавляются в проект библиотеки веб-контроля. Отрисовка элемента управления полностью контролируется программистом путем переопределения метода Render .

Мои мысли..

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

  • У вас мало / нет контроля над выводом HTML, что затрудняет «отладку».
  • В CreateChildControls (и последующие методы) могут получить реальные заняты Controls.Add (MyControl) во всем мире.
  • Я обнаружил, что визуализация таблиц (будь то макет или контент) довольно неудобна.

Вопросы)..

Итак, я признаю, что я новичок в этом, поэтому я мог бы быть далеко не в основе с некоторыми из моих замечаний, отмеченных выше ...

  • Вы используете композиты?
  • Есть ли у вас какие-нибудь хитрые приемы для управления выводом HTML?
  • Вы просто говорите «к черту» и создаете настраиваемый элемент управления?

Это то, о чем я хочу по-настоящему твердо подумать, поскольку знаю, насколько хорошая разработка средств управления может сократить общее время разработки.

Жду ваших ответов ^ _ ^

Ответов (6)

Решение

Я говорю, продолжайте настраивать рендеринг элемента управления. Я нахожу, что в большинстве случаев композицию легче сделать и использовать в UserControl, но все, что выходит за рамки этого, требует более точного контроля (каламбур непреднамеренно), чтобы заслужить вашу собственную стратегию рендеринга.

Могут быть элементы управления, которые достаточно просты, чтобы заслужить составную часть (например, текстовое поле в сочетании с datepicker на основе javascript / dhtml, например), но помимо этого одного примера, похоже, что настраиваемые элементы управления - это путь.

Я часто использую составные элементы управления. Вместо переопределения Render или RenderContents просто назначьте каждому элементу управления CssClass и используйте таблицы стилей. Для нескольких Controls.Add я использую метод расширения:

//Controls.Add(c1, c2, c3)
static void Add(this ControlCollection coll, params Control[] controls)
 { foreach(Control control in controls) coll.Add(control);
 }

Для быстрого и грязного рендеринга я использую что-то вроде этого:

writer.Render(@"<table>
                   <tr><td>{0}</td></tr>
                   <tr>
                       <td>", Text);
control1.RenderControl(writer);
writer.Render("</td></tr></table>");

Для инициализации свойств элемента управления я использую синтаксис инициализатора свойств:

childControl = new Control {  ID="Foo"
                            , CssClass="class1"
                            , CausesValidation=true;
                           };

Использование настраиваемых составных элементов управления имеет смысл в ситуации, когда у вас есть большое веб-приложение и вы хотите повторно использовать большие фрагменты во многих местах. Тогда вы должны добавить только дочерние элементы управления к тем, которые вы разрабатываете, вместо того, чтобы повторяться. Недавно я работал над большим проектом, и мы сделали следующее:

  • Каждый составной элемент управления имеет контейнер. Используется как обертка для всего, что находится внутри элемента управления.
  • У каждого составного элемента управления есть шаблон. Файл ascx (без директивы <% Control%>), который содержит только разметку для шаблона.
  • Контейнер (сам по себе являющийся элементом управления) инициализируется из шаблона.
  • Контейнер предоставляет свойства для всех других элементов управления в шаблоне.
  • Вы используете this.Controls.Add ([the_container]) только в своем составном элементе управления.

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

Вот еще один метод расширения, который я использую для пользовательского рендеринга:

 public static void WriteControls
        (this HtmlTextWriter o, string format, params object[] args)
 { 
    const string delimiter = "<2E01A260-BD39-47d0-8C5E-0DF814FDF9DC>";
    var controls  = new Dictionary<string,Control>();

    for(int i =0; i < args.Length; ++i)
    { 
       var c = args[i] as Control; 
       if (c==null) continue;
       var guid = Guid.NewGuid().ToString();
       controls[guid] = c;
       args[i] = delimiter+guid+delimiter;
    }

    var _strings = string.Format(format, args)
                         .Split(new string[]{delimiter},
                                StringSplitOptions.None);
    foreach(var s in _strings)
    { 
       if (controls.ContainsKey(s)) 
           controls[s].RenderControl(o);
       else 
           o.Write(s);
    }
}

Затем для рендеринга пользовательской композиции в методе RenderContents () я пишу следующее:

protected override void RenderContents(HtmlTextWriter o)
{ 
    o.WriteControls
         (@"<table>
               <tr>
                    <td>{0}</td>
                    <td>{1}</td>
               </tr>
             </table>"
            ,Text
            ,control1);
 }

Роб, ты прав. Упомянутый мной подход - своего рода гибрид. Преимущество наличия файлов ascx заключается в том, что в каждом проекте, который я видел, дизайнеры будут чувствовать себя наиболее комфортно, редактируя фактическую разметку, а с ascx вы и дизайнер можете работать отдельно. Если вы не планируете вносить фактические изменения CSS / разметки / дизайна самих элементов управления позже, вы можете использовать настраиваемый элемент управления. Как я уже сказал, мой подход актуален только для более сложных сценариев (и здесь, вероятно, вам понадобится дизайнер :))

Возможно, вы сможете использовать эту технику, чтобы упростить время разработки:

http://aspadvice.com/blogs/ssmith/archive/2007/10/19/Render-User-Control-as-String-Template.aspx

Обычно вы создаете экземпляр пользовательского элемента управления во время выполнения с помощью метода LoadControl, затем передаете ему какой-либо пакет состояний, а затем присоединяете его к дереву элементов управления. Таким образом, ваш составной элемент управления фактически будет функционировать как больше контроллер, а файл .ascx будет похож на представление.

Это избавит вас от необходимости создавать экземпляр всего дерева элементов управления и стилизовать элемент управления на C#!