Инициализация дочернего элемента управления в пользовательском композите в ASP.NET
-
02-07-2019 - |
Вопрос
Часть серии элементов управления, над которой я работаю, очевидно, предполагает объединение некоторых из них в составные элементы.Я быстро начинаю понимать, что это требует внимания (для меня это все в новинку!) :)
у меня в основном есть 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
сбор композита.
Итак, у меня было две вещи:
- я переопределил
Controls
метод доступа к свойству для композиции, чтобы вернуть этоPanel
Коллекция элементов управления, так как я не хочу идтиctl.Controls[0].Controls[0]
чтобы получить фактический контроль, который я хочу. Я удалил это, но мне нужно разобраться. - я не добавил
Panel
кControls
коллекция, Я сейчас это сделал.
Итак, теперь это работает, однако, как мне получить Controls
свойство композита возвращать элементы в Panel
, а не Panel
сам?