Часть серии элементов управления, над которыми я работаю, очевидно, включает в себя объединение некоторых из них в композиты. Я быстро начинаю понимать, что это нужно учитывать (для меня это все в новинку!) :)
У меня в основном есть элемент управления 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;
}
}
Надеюсь, это поможет прояснить ситуацию. Извинения.
Верно, я немного поигрался с элементом управления, поместив один внутри композиции, а другой снаружи. Затем я получил статус Page при главном событии в жизненном цикле элемента управления и отобразил его на странице.
Автономная версия работает нормально, и страница инициализируется должным образом. Однако вложенный в Composite другой. Это событие OnLoad вообще не запускается! Итак, я предполагаю, что Брэд, вероятно, прав в том, что я неправильно настраиваю иерархию управления, может ли кто-нибудь дать совет относительно того, что мне не хватает? Разве метода Panel недостаточно? (ну явно не так ли ?!): D
Спасибо за помощь, ребята, спасибо :)





Я не вижу, чтобы вы где-либо добавляли свои элементы управления в коллекцию 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: он просто помещает скрипт на страницу.
Верно, я начал играть и решил, что что-то не так с моим экземпляром элемента управления, поскольку Longhorn был прав, я мог создавать ссылки на скрипты в OnLoad (а я не мог), и Брэд был прав в том, что мне нужно убедиться, что моя иерархия Controls поддерживается путем добавления в коллекцию Controls композита.
Итак, у меня здесь было две вещи:
Controls для композита, чтобы вернуть эту коллекцию элементов управления Panel, так как я не хочу переходить на ctl.Controls[0].Controls[0], чтобы получить фактический элемент управления, который я хочу. Я удалил это, но мне нужно разобрать это.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;
}
}
И это довольно просто, когда знаешь как! :)
Следующий: Поддержка области времени разработки!
Я думаю, вы можете что-то понять (сейчас взломать код!) - но я немного сбит с толку, происходит событие Load до событие Render (когда я вызываю код для добавления RegisterClientScriptBlock) - так что он должен быть там , или я что-то упускаю?