Инициализация дочернего элемента управления в настраиваемом составе в ASP.NET

Часть серии элементов управления, над которыми я работаю, очевидно, включает в себя объединение некоторых из них в композиты. Я быстро начинаю понимать, что это нужно учитывать (для меня это все в новинку!) :)

У меня в основном есть элемент управления StyledWindow, который по сути является прославленным Panel с возможностью выполнять другие операции (например, добавлять границы и т. д.).

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

    protected override void CreateChildControls()
    {
        _panel = new Panel();

        if (_editable != null)
            _editable.InstantiateIn(_panel);

        _regions = new List<IAttributeAccessor>();
        _regions.Add(_panel);
    }

Проблемы возникли сегодня, когда я попытался вложить в него более сложный элемент управления. Этот элемент управления использует ссылку на страницу, поскольку он внедряет JavaScript, чтобы сделать ее более быстрой и отзывчивой (RegisterClientScriptBlock - единственная причина, по которой мне нужна ссылка на страницу).

Теперь это вызывало ошибки "объект null", но я локализовал это до метода рендеринга, который, конечно, пытался вызвать метод для объекта [null] Page.

Что меня сбивает с толку, так это то, что этот элемент управления отлично работает как автономный, но когда его помещают в StyledWindow, все идет ужасно неправильно!

Итак, похоже, что мне чего-то не хватает в моем StyledWindow или ChildControl. Есть идеи?

Обновлять

Как совершенно справедливо заметил Брэд Уилсон, вы не видите элементы управления, добавляемые в коллекцию Controls. Это то, для чего предназначен _panel, он должен был справиться с этим для меня, в основном затем переопределить Controls (я получил это где-то из руководства):

    Panel _panel;    // Sub-Control to store the "Content".
    public override ControlCollection Controls
    {
        get
        {
            EnsureChildControls();
            return _panel.Controls;
        }
    }

Надеюсь, это поможет прояснить ситуацию. Извинения.

Обновить после Ответ Longhorn213

Верно, я немного поигрался с элементом управления, поместив один внутри композиции, а другой снаружи. Затем я получил статус Page при главном событии в жизненном цикле элемента управления и отобразил его на странице.

Автономная версия работает нормально, и страница инициализируется должным образом. Однако вложенный в Composite другой. Это событие OnLoad вообще не запускается! Итак, я предполагаю, что Брэд, вероятно, прав в том, что я неправильно настраиваю иерархию управления, может ли кто-нибудь дать совет относительно того, что мне не хватает? Разве метода Panel недостаточно? (ну явно не так ли ?!): D

Спасибо за помощь, ребята, спасибо :)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
3 428
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Я не вижу, чтобы вы где-либо добавляли свои элементы управления в коллекцию Controls, что объясняло бы, почему они не могут получить доступ к странице (поскольку они никогда официально не размещались на странице).

Я всегда помещал вызовы JavaScript в функцию OnLoad. Как показано ниже.

protected override void OnLoad(EventArgs e)
{

    // Do something to get the script
    string script = GetScript();

    this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "SomeJavaScriptName", script);

    // Could also use this function to determine if the script has been register. i.e. more than 1 of the controls exists
    this.Page.ClientScript.IsClientScriptBlockRegistered("SomeJavaScriptName");

    base.OnLoad(e);
}

Если вы все же хотите выполнить рендеринг, вы можете просто написать скрипт в ответе. Именно это и делает RegisterScriptBlock: он просто помещает скрипт на страницу.

Я думаю, вы можете что-то понять (сейчас взломать код!) - но я немного сбит с толку, происходит событие Load до событие Render (когда я вызываю код для добавления RegisterClientScriptBlock) - так что он должен быть там , или я что-то упускаю?

Rob Cooper 25.09.2008 12:32

Верно, я начал играть и решил, что что-то не так с моим экземпляром элемента управления, поскольку Longhorn был прав, я мог создавать ссылки на скрипты в OnLoad (а я не мог), и Брэд был прав в том, что мне нужно убедиться, что моя иерархия Controls поддерживается путем добавления в коллекцию Controls композита.

Итак, у меня здесь было две вещи:

  1. Я переопределил аксессор свойства Controls для композита, чтобы вернуть эту коллекцию элементов управления Panel, так как я не хочу переходить на ctl.Controls[0].Controls[0], чтобы получить фактический элемент управления, который я хочу. Я удалил это, но мне нужно разобрать это.
  2. Я не добавлял Panel в коллекцию Controls, Я сделал это.

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

Ответ принят как подходящий

Решено!

Правильно, я был полон решимости сделать это сегодня же! Вот мои мысли:

  • Я подумал, что использование Panel было чем-то вроде взлома, поэтому мне следует удалить его и выяснить, как это делается на самом деле.
  • Я не хотел делать что-то вроде MyCtl.Controls[0].Controls для доступа к элементам управления, добавленным в композит.
  • Я хотел, чтобы эта чертова штука заработала!

Итак, я начал поиск и нажал MSDN, это искусство оказался полезным В САМОМ ДЕЛЕ (то есть почти как копирование и вставка, и хорошо объяснил - что-то MSDN традиционно плохо получается). Хороший!

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

Вот что у меня есть сейчас:

  • Я узнал, что использую неправильный термин. Я должен был назвать это Шаблонный элемент управления. Хотя шаблонные элементы управления технически являются составными частями, между ними есть четкое различие. Шаблонные элементы управления могут определять интерфейс для добавляемых к ним элементов.
  • Шаблонные элементы управления очень мощные и на самом деле довольно быстро и легко настраиваются, как только вы их разберетесь!
  • Я еще немного поиграю с поддержкой дизайнера, чтобы убедиться, что полностью все это понимаю, а затем напишу сообщение в блоге :)
  • Элемент управления «Шаблон» используется для указания интерфейса для шаблонных данных.

Например, вот разметка ASPX для шаблонного элемента управления:

<cc1:TemplatedControl ID = "MyCtl" runat = "server">
    <Template>
        <!-- Templated Content Goes Here -->
    </Template>
</cc1:TemplatedControl>   

Вот код, который у меня есть сейчас

public class DummyWebControl : WebControl
{
    // Acts as the surrogate for the templated controls.
    // This is essentially the "interface" for the templated data.
}

В TemplateControl.cs ...

    ITemplate _template;
    // Surrogate to hold the controls instantiated from 
    // within the template.
    DummyWebControl _owner;

    protected override void CreateChildControls()
    {
        // Note we are calling base.Controls here
        // (you will see why in a min).
        base.Controls.Clear();
        _owner = new DummyWebControl();

        // Load the Template Content
        ITemplate template = _template;
        if (template == null)
            template = new StyledWindowDefaultTemplate();
        template.InstantiateIn(_owner);

        base.Controls.Add(_owner);
        ChildControlsCreated = true;
    }

Затем, чтобы обеспечить легкий доступ к элементам управления объекта [Surrogate]:

(вот почему нам нужно было очистить / добавить в base.Controls)

    public override ControlCollection Controls
    {
        get
        {
            EnsureChildControls();
            return _owner.Controls;
        }
    }

И это довольно просто, когда знаешь как! :)

Следующий: Поддержка области времени разработки!

Другие вопросы по теме