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"是我需要页面引用的唯一原因)。
现在,这导致了"对象空"错误,但我将其本地化为render方法,这当然是试图针对[null]Page
对象调用该方法。
令我感到困惑的是,该控件可以作为独立控件正常工作,但是当将其放置在" StyledWindow"中时,一切都会变得非常错误!
因此,似乎我的StyledWindow或者ChildControl中缺少某些内容。有任何想法吗?
更新
正如Brad Wilson正确指出的那样,我们看不到控件被添加到Controls
集合中。这就是_panel的用途,在那里是为我处理的,基本上是重写Controls(我从某处的指南那里得到):
Panel _panel; // Sub-Control to store the "Content". public override ControlCollection Controls { get { EnsureChildControls(); return _panel.Controls; } }
我希望这有助于澄清问题。道歉。
在Longhorn213的答案之后更新
是的,我一直在做一些控制工作,将其中一个放置在组合中,另一个放置在外部。然后,我在生命周期控件的事件主要事件中获得Page的状态,并将其呈现给页面。
独立运行正常,页面已按预期初始化。但是,嵌套在Composite中的那个是不同的。它的OnLoad
事件根本没有被触发!因此,我猜测Brad可能是正确的,因为我没有正确设置控件层次结构,有人可以就我所缺少的内容提供一些建议吗?面板方法不够吗? (嗯,显然不是吗?!):D
感谢帮助,感激不尽:)
解决方案
我看不到我们将控件添加到Controls集合的任何位置,这可以解释为什么它们无法访问Page(因为它们从未被正式放置在页面上)。
我一直把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上创建脚本引用(我不能),而Brad是正确的。需要通过添加到组合的"控件"集合中来确保维护我的"控件"层次结构。
所以,我在这里有两件事:
- 我已经覆盖了复合控件的"控件"属性访问器以返回此"面板"的控件集合,因为我不想去ctl.Controls [0] .Controls [0]来获取实际的控件想。我已经删除了它,但是我需要对它进行排序。
- 我没有将
Panel
添加到Controls
集合中,现在已经完成了。
因此,它现在可以工作了,但是,如何获得复合控件的"控件"属性以返回"面板"中的项目,而不是返回"面板"本身?
是的,我下定决心今天要破解!这是我的想法:
- 我认为使用
Panel
有点麻烦,所以我应该将其删除并找出它是如何完成的。 - 我不想做类似MyCtl.Controls [0] .Controls之类的操作来访问添加到组合中的控件。
- 我想要那该死的东西工作!
因此,我搜索并打了MSDN,这个文章确实很有帮助(即就像几乎复制'n'粘贴一样,并且很好地解释了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; } }
这就差不多了,只要我们知道如何即可! :)
下一步:设计时区支持!