Как создать пользовательский элемент управления ASP.NET с внутренними свойствами, используемыми с разметкой, подобной UpdatePanel? - PullRequest
9 голосов
/ 05 ноября 2010

Я создаю пользовательский элемент управления, который хотел бы иметь внутренние свойства, а также обычные атрибуты.Хотя фактическая функция элемента управления не имеет никакого отношения, скажем, к UpdatePanel, я пытаюсь создать что-то с похожей разметкой ASPX.Разработчик, проектирующий страницу, должен иметь возможность использовать мой элемент управления, например:

<ns:MyControl ID="someID" runat="server" SomeOtherAttribute="true">
  <ContentTemplate>
    <asp:Label ID="someLabel" runat="server" Text="Normal page markup and controls should go here" /><br />
    <p>This should be OK too.</p>
  </ContentTemplate>
  <ControlEvent ControlName="idOfOtherControl" Event="Click" />
  <ControlEvent ControlName="idOfSomeOtherControl" Event="MouseOver" />
</ns:MyControl>

Также приемлемо было бы обернуть теги ControlEvent в какой-либо другой тег, более похоже на то, что происходит при использовании UpdatePanel:

<ns:MyControl ID="someID" runat="server" SomeOtherAttribute="true">
  <ContentTemplate>
    <asp:Label ID="someLabel" runat="server" Text="Normal page markup and controls should go here" /><br />
    <p>This should be OK too.</p>
  </ContentTemplate>
  <ControlEvents>
    <ns:ControlEvent ControlName="idOfOtherControl" Event="Click" />
    <ns:ControlEvent ControlName="idOfSomeOtherControl" Event="MouseOver" />
  </ControlEvents>
</ns:MyControl>

Но тег ControlEvents должен разрешать только этот конкретный тег, а не обычную разметку сервера или что-либо еще.

Я понимаю, как получить содержимое внутри ContentTemplate для рендеринга (в моем Page_Init, я использую метод ITemplate.InstantiateIn(placeholderControl)).Эта часть отлично работает.У меня проблемы с тем, чтобы заставить работать ControlEvent часть.Я могу создать внутреннее свойство в коде, например:

[TemplateInstance(TemplateInstance.Multiple)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(ControlEvent))]
public List<ControlEvent> ControlEvents { get; set; }

При этом ASP.NET, похоже, понимает, что мне нужен тег ControlEvents.Но я не могу распознать свойства, как внутренние, так и атрибуты.Вместо этого, если я пытаюсь выполнить разметку первого типа, я получаю ошибку синтаксического анализатора во время выполнения: «Свойство ControlEvents не имеет свойства с именем ControlName».Если я попробую второй тип разметки, я получу NullReferenceException как ошибку синтаксического анализатора во время выполнения с ошибкой, сгенерированной в строке <ns:ControlEvent>.

Я проверил онлайн, но у меня нетЯ нашел хороший пример или объяснение того, как выполнить то, что я пытаюсь сделать с ControlEvent или ControlEvents.Что мне не хватает?Может ли кто-нибудь указать мне хороший пример здесь?

Спасибо!

Редактировать:

Оказалось, что некоторые проблемы были связаны с тем, какЯ зарегистрировал элемент управления на странице, используя его.Если бы я использовал:

<%@ Register Src="~/Controls/MyControl.ascx" TagPrefix="ns" TagName="MyControl" %>

Оказалось, что сам элемент управления был распознан в разметке, но ns:ControlEvent не было.Если я изменил Register на:

<%@ Register Namespace="Namespace.Controls" TagPrefix="ns" Assembly="MyAssembly" %>

, то это сработало бы до понимания самого элемента управления (при условии, что runat="server" был включен в теги ns:ControlEvent).Однако дочерние элементы управления MyControl больше не создавались и не отображались, а события элемента управления, такие как Page_Init и Page_Load, не запускались.

После долгих раздумий я понял, что мне кажется, чтонужны обе Register директивы.Это выглядит как грязное «решение», и оно на самом деле даже не решает все, так как (по крайней мере, некоторая часть разметки в моем элементе управления не отображается), хотя шаблонный элемент управления (ContentTemplate), кажется, работаетснова.

Какие вещи я мог бы упустить здесь, чтобы сделать этот элемент управления менее беспорядочным и сделать этот элемент управления действительно правильно отображать все?

1 Ответ

10 голосов
/ 07 ноября 2010

Свойства должны быть указаны как Collection, а не List;кроме этого, самое важное, что следует помнить, это то, что для родительского элемента управления должен быть установлен атрибут [ParseChildren(true)], иначе коллекция будет null.

.следующий (серверный) образец работает как положено:

   public class ControlEvent
    {
        public string ControlName { get; set; }
        public string Event { get; set; }
    }

    [ParseChildren(true)]
    public class SampleControl : System.Web.UI.Control, INamingContainer
    {
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(SampleControl))]
        public ITemplate ContentTemplate { get; set; }

        [MergableProperty(false), PersistenceMode(PersistenceMode.InnerProperty), DefaultValue((string)null)]
        public Collection<ControlEvent> ControlEvents { get; set; }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            if (ContentTemplate != null)
                ContentTemplate.InstantiateIn(this);

            if (null != ControlEvents)
                foreach (ControlEvent e in ControlEvents)
                    Controls.Add(new Label() { Text = string.Format("ControlName:{0}, Event:{1}", e.ControlName, e.Event) });
        }
    }

HTH.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...