动态添加控件到模板化用户控件?
几周前,我创建了一个模板化用户控件,大部分基于此处的示例: http://msdn.microsoft.com/en- us/library/36574bf6(v=VS.90).aspx
区别在于我没有实现“MessageContainer”类,因为我只想要一个空模板,我可以添加我想要的任何控件到设计时。
这个 TUC 运行得很好,但我遇到了一个我在创建这个东西时没有预料到的场景。需要将此 TUC 动态添加到页面,这意味着我还需要在 TUC 模板中动态添加控件。
我在这里找到了另一个关于如何动态创建模板并将其添加到模板化控件的示例: http://msdn.microsoft.com/en- us/library/y0h809ak(v=vs.71).aspx
第二篇示例文章仅讨论“DataList、Repeater 和 DataGrid 控件”,但我认为因为我使用的是这里的ITemplate接口,应该是同一个东西。
但是,我无法使其正常工作,我不断收到“对象引用未设置到对象实例”的消息。当我尝试填充 TUC 时出错。
这就是我正在做的...
就像上面的示例一样,我创建了一个 ITemplate 类:
public class XPCTemplate : ITemplate
{
private readonly Control _control;
public XPCTemplate(Control control)
{
_control = control;
}
public void InstantiateIn(Control container)
{
container.Controls.Add(_control);
}
}
然后,在测试页面代码隐藏中,我尝试动态加载并显示 TUC:
ExpandCollapseRegion xpcRegion; // The Templated User Control
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder ph;
// .... code here to dynamically create some labels, textboxes, etc. ....
// Create an instance of the TUC
xpcRegion = new ExpandCollapseRegion();
// Pass into the TUC's template the controls dynamically created above
xpcRegion.LayoutTemplate = new XPCTemplate(ph);
// add the dynamic TUC to the page
phDynamicUC.Controls.Add(xpcRegion);
phDynamicUC.Controls.Add(new LiteralControl("<br />"));
}
测试页面 HTML 源:
<body>
<form id="form1" runat="server">
<div>
Dynamically Loading User Control
<br />
<asp:PlaceHolder ID="phDynamicUC" runat="server" />
</div>
</form>
</body>
当我运行页面时,我在“container.Controls.Add(_control);”上收到“对象引用未设置到对象实例”错误XPCTemplate 类的行。当我调试测试页和 TUC 控件时,TUC 的代码在 TUC 的 Page_Init() 方法期间将 XPCTemplate 接收到其 LayoutTemplate 中,但是当随后立即触发 XPCTemplate 中的 InstantiateIn() 事件时,“容器”参数为无效的。
我不确定为什么会发生这种情况,就像 XPCTemplate 类的 InstantiateIn() 方法试图在 TUC 中实际设置 PlaceHolder 控件,而不仅仅是传递内容。也许这应该是这样,而我在 TUC 方面缺少一些允许这种行为的东西?
这是我创建的第一个 TUC,同样也是第一次尝试动态填充/加载它,所以我确信我缺少完成此任务所需的东西。非常感谢任何帮助。
——安德鲁
A few weeks back I created a Templated User Control, for the most part based on the example here:
http://msdn.microsoft.com/en-us/library/36574bf6(v=VS.90).aspx
The difference is that I did not implement the "MessageContainer" class as I wanted just an empty template that I could add whatever controls I wanted to at design time.
This TUC has been working great, but I ran into a scenario I hadn't anticipated when I created the thing. The need to dynamically add this TUC to a page, which means that I would need to dynamically add the controls within the template of the TUC as well.
I found another example here on how to dynamically create a Template and add it to the Templated Control:
http://msdn.microsoft.com/en-us/library/y0h809ak(v=vs.71).aspx
This second example article discusses only the "DataList, Repeater, and DataGrid controls" but I figure since I am using the ITemplate interface here, it should be the same thing.
However, I am unable to get this to work, I keep getting an "Object reference not set to an instance of an object." error when I attempt to populate the TUC.
Here's what I am doing....
Like the example above I created an ITemplate class:
public class XPCTemplate : ITemplate
{
private readonly Control _control;
public XPCTemplate(Control control)
{
_control = control;
}
public void InstantiateIn(Control container)
{
container.Controls.Add(_control);
}
}
Then, in the test page code-behind I attempt to load up and display the TUC dynamically:
ExpandCollapseRegion xpcRegion; // The Templated User Control
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder ph;
// .... code here to dynamically create some labels, textboxes, etc. ....
// Create an instance of the TUC
xpcRegion = new ExpandCollapseRegion();
// Pass into the TUC's template the controls dynamically created above
xpcRegion.LayoutTemplate = new XPCTemplate(ph);
// add the dynamic TUC to the page
phDynamicUC.Controls.Add(xpcRegion);
phDynamicUC.Controls.Add(new LiteralControl("<br />"));
}
Test page HTML Source:
<body>
<form id="form1" runat="server">
<div>
Dynamically Loading User Control
<br />
<asp:PlaceHolder ID="phDynamicUC" runat="server" />
</div>
</form>
</body>
When I run the page, I get the "Object reference not set to an instance of an object" error on the "container.Controls.Add(_control);" line of the XPCTemplate class. When I debug the test page and TUC control, the code of the TUC receives the XPCTemplate into its LayoutTemplate during the TUC's Page_Init() method, but when the InstantiateIn() event back in the XPCTemplate fires immediately afterwards, the "container" argument is NULL.
I'm not sure why this is happening, it's like the InstantiateIn() method of the XPCTemplate class is trying to actually set the PlaceHolder control within the TUC rather than just passing the contents. Maybe this is supposed to be the way and I am missing something on the TUC side to allow this behavior?
This is the first TUC I have created and likewise the first time trying to dynamically fill/load it, so I am sure I am missing something needed to accomplish this. Any help is greatly appreciated.
-- Andrew
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
找到了问题的解决方案,这就是我加载 TUC 的方法。
错误:
正确:
通过这个简单的更改就可以解决问题。另外,我发现我可以通过使用
CompiledTemplateBuilder()
方法来放弃对自定义ITemplate
类的需要。确实简化了代码。——安德鲁
Found the solution to the problem, which was how I was loading the TUC.
Incorrect:
Correct:
Making this simple change took care of the problem. Also, found that I could forego the need for a custom
ITemplate
class by using theCompiledTemplateBuilder()
method. Really simplifies the code.-- Andrew
我相信问题是您还没有实例化您传递到模板中的 PlaceHolder ph 值。因此,它抱怨的行是因为它无法将控件添加到 PlaceHolder,因为它为空/无。
另外,我相信您需要将占位符放在某个地方。否则,您将向容器添加项目,而该容器从未添加到页面。
I believe the problem is that you haven't instantiated your PlaceHolder ph that you are passing into your template. So, the line it is complaining on is because it can't add the control to the PlaceHolder because it is null/nothing.
Also, I believe you're going to need to put your placeholder somewhere. Otherwise, you're adding items to a container that is never added to the page.