Вопрос времени разработки пользовательского элемента управления Asp.Net

Я разрабатываю набор настраиваемых элементов управления, один из которых является «родительским», а все остальные должны быть добавлены в свойство ITemplate этого родительского элемента.

Но на странице во время разработки я могу видеть с помощью intellisense другие элементы управления на уровне страницы и теоретически могу добавлять их везде.

Я хочу имитировать поведение asp: Table и asp: TableRow, вы не можете напрямую добавить asp: TableRow вне asp: Table ...

Есть ли способ достичь этого? Большое спасибо!

изменить: я частично решил с предложением КП, но если вы читаете комментарий, это не «настоящий» способ сделать это (я думаю). Никто не знает, как это сделать? :(


person tanathos    schedule 09.02.2010    source источник


Ответы (2)


Я отредактировал весь ответ на основе нашего обсуждения. Вот рабочий и проверенный пример. У нас есть два элемента управления - ParentControl и ChildControl. ParentControl отображается через Intellisense, где ChildControl отображается только как дочерний элемент ParentControl, как вы хотели. Для простых целей визуализации дочерние элементы визуализируются как теги li и выводят свое свойство text. Родительский элемент управления гарантирует, что каждому дочернему элементу будет предложено выполнить рендеринг во время его собственного RenderContents события.

Дочерний контроль:

using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TestControls
{
    [ToolboxItem(false), Bindable(false)]
    public class ChildControl : WebControl
    {
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer);

            //render the text property as a list item for example's sake
            writer.RenderBeginTag(HtmlTextWriterTag.Li);
            writer.Write(this.Text);
            writer.RenderEndTag();
        }

        [Browsable(true)]
        public string Text { get; set; }
    }
}

Родительский контроль:

using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TestControls
{
    [ToolboxData("<{0}:ParentControl runat=\"server\"></{0}:ParentControl>")]
    [DefaultProperty("Children"), ParseChildren(true, "Children")]
    public class ParentControl : WebControl
    {
        private List<ChildControl> _children;

        protected override void RenderContents(HtmlTextWriter writer)
        {
            base.RenderContents(writer);

            //create a div, and write some sample text
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.Write("Parent Control. Children:");

            //create a ul, and ask each child control to render
            writer.RenderBeginTag(HtmlTextWriterTag.Ul);

            foreach (ChildControl child in _children)
            {
                child.RenderControl(writer);
            }

            //close all tags
            writer.RenderEndTag();
            writer.RenderEndTag();
        }

        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public virtual List<ChildControl> Children
        {
            get
            {
                if (_children == null)
                    _children = new List<ChildControl>();

                return _children;
            }
        }
    }
}

В своей разметке я зарегистрировал элементы управления через пространство имен:

<%@ Register TagPrefix="test" Namespace="TestControls" %>

А потом добавил разметку:

<test:ParentControl ID="test" runat="server">
    <test:ChildControl ID="child" Text="Hello World from Child 1" runat="server" />
    <test:ChildControl ID="child2" Text="Hello World from Child 2" runat="server" />
</test:ParentControl>

В приведенной выше разметке Intellisense выбирает внешний родительский элемент управления, но не видит дочерний элемент управления. Когда курсор оказывается внутри родительского элемента управления, Intellisense при желании выбирает тег ChildControl.

Окончательный результат:

Родительский контроль. Дети:

* Hello World from Child 1
* Hello World from Child 2

Кроме того, вот хорошая статья о том, как работает весь процесс создания интеллекта, по которой я создал выше.

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

person KP.    schedule 09.02.2010
comment
в свой субэлемент управления я добавил [ToolboxItem (false)], а затем показал его как свойство родительского элемента управления с атрибутом [PersistenceMode (PersistenceMode.InnerProperty)]. Я думаю, что это неправильный способ сделать это, но на данный момент это единственный способ помочь ... - person tanathos; 09.02.2010
comment
Почему это «неправильный» способ? Я верю, что вы на правильном пути. Другой пример с использованием тех же атрибутов: robertwray. co.uk/blog/2008/02/ - person KP.; 09.02.2010
comment
потому что таким образом мой субэлемент управления не отображает себя автоматически, это простое свойство его родителя, я должен реализовать логику рендеринга на родительском уровне ... честно говоря, я не понимаю, как asp: TableRow и asp: Table работает, я видел их код в отражателе, но я не нашел причины, по которой TableRow становится невидимым за пределами Table .... - person tanathos; 09.02.2010
comment
@tanathos - достаточно честно. Я отредактировал ответ с хорошей ссылкой, которая описывает, как генерируется intellisense. ToolboxItem выглядит как единственный атрибут, который вам нужен, чтобы скрыть элемент управления от видимости верхнего уровня в вашей разметке. - person KP.; 10.02.2010
comment
Да, похоже, что это связано с ToolBoxItem. Если я установил для него значение false, субэлемент управления не отображается в intellisense (вообще), но элемент управления работает, он отображается в html, даже если тег не распознается VS. Но я пробовал каждую комбинацию, я не могу заставить ее отображаться только в родительском элементе управления ... кажется, ничего или все ... Наконец, я думаю, что сейчас я реализую систему рендеринга, основанную на атрибутах. В любом случае, спасибо за время, которое вы потратили, помогая мне! - person tanathos; 10.02.2010
comment
Без проблем. Меня раздражало отсутствие решения, поэтому я написал очень простые элементы управления в рабочем примере. См. Выше! :) - person KP.; 10.02.2010
comment
Здорово! Это работает хорошо! Делаю именно то, что мне нужно. С помощью базового трюка вы также можете расширить поддержку, чтобы использовать больше элементов управления внутри родительского элемента, просто создав новый элемент управления, унаследованный от ChildControl или базового класса. Еще раз спасибо, чувак! - person tanathos; 10.02.2010

Я делал это раньше, но у меня нет кода. Могу сказать, что я понял это, используя Reflector во встроенном элементе управления ASP.NET Datagrid. Мне удалось реконструировать взаимосвязь между «содержащимся» («строкой») и «контейнером» («сеткой»). Вы должны упорядочить классы вместе очень определенным образом, используя атрибуты.

person Dave Swersky    schedule 09.02.2010