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

StackOverflow https://stackoverflow.com/questions/127794

Вопрос

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

у меня в основном есть 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

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

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

Спасибо за вашу помощь, ребята, ценю :)

Это было полезно?

Решение 3

Решено!

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

  • Я думал, что использование 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]:

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

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

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

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

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

Я не вижу, чтобы вы где-либо добавляли свои элементы управления в коллекцию 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: он просто встраивает скрипт на страницу.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top