我有一个表示嵌套层次结构的类(MyClass),因此该类有一个属性,它是MyClass的集合。 MyClass还有一个标题属性
为了在网页上显示,我希望创建一个具有转发器的用户控件。在项目模板中,我将使用文字来显示title属性,并且在转发器的ItemCreated事件上,我将创建usercontrol的新实例,并将其添加到转发器中的当前项目中。
我的问题是,当usercontrol中的Page_Load事件触发时,如果控件是动态添加的,则repMyClass转发器poroperty为null,即使我调用EnsureChildControls。我在这里错过了什么吗?如果我创建一个转发器并将我的userctonrol放入项目模板中,它可以正常工作。我不能让它动态地工作吗?
用户控制:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyControl.ascx.cs" Inherits="MyControl" %>
Items:<br/>
<asp:Repeater ID="repMyClass" runat="server" EnableViewState="false"
OnItemCreated="repMenuItems_ItemCreated">
<HeaderTemplate><ul><HeaderTemplate>
<ItemTemplate>
<li><%# Eval("Title") %>
<div><asp:PlaceHolder ID="SubItemPlaceholder" runat="server" /></div>
</li></ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
用户控制代码:
public partial class MyControl: System.Web.UI.UserControl
{
public IEnumerable<MyClass> ChildItems { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
this.repMyClass.DataSource = ChildItems;
this.repMyClass.DataBind();
}
protected void repMenuItems_ItemCreated(object Sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
//Get the MyClass instance for this repeater item
MyClass mcCurrent = (MyClass)e.Item.DataItem;
//If the MyClass instance has child instances
if (mcCurrent.Children != null && mcCurrent.Children.Length > 0)
{
//Add a new user control and set it's property so it can bind
PlaceHolder ph = (PlaceHolder)e.Item.FindControl("SubItemPlaceholder");
MyControl ctl = (MyControl)Page.LoadControl(typeof(MyControl),new object[] {});
ctl.ChildItems = mcCurrent.Children;
ph.Controls.Add(ctl);
}
}
}
}
答案 0 :(得分:3)
我很久以前就已经使用Accordions创建了嵌套报告。
在索引中,当您想要动态添加用户控件实例时:
// Declare Placeholder
PlaceHolder ph = (PlaceHolder)e.Item.FindControl("SubItemPlaceholder")
// Adding some literal controls to header
ph.Controls.Add(new LiteralControl("This is the accordion header!!"));
// Declare new control variable
crt = new Control();
// Load up your User Control
crt = LoadControl("~/MyControl.ascx");
// Check if it has loaded properly
if (crt != null)
{
// GET / SET any custom properties of the User Control
((myClass)crt).title = "Welcome";
// Add the new User Control to the placeholder's controls collection
ph.Controls.Add(crt);
}
注意: 在用户控件中,您必须在声明标记
中添加“ClassName”<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="myTest" ClassName="myClass" %>
此外,您希望在动态创建实例时公开的任何属性,您可以按如下方式声明它们:
public string title { get; set; }
因此,如果您想在为“repMyClass”创建时强制设置一个值,您可以将其设置为属性,并以编程方式为其指定任何值。
答案 1 :(得分:0)
您可以在控件中创建另一个构造函数,该构造函数接受您想要的属性并在load事件中使用它,然后在LoadControl()调用中将它传递给当前空的对象数组。
另一种方法是在属性的setter中触发逻辑,而不是在控件的Load事件中触发,因为这里实际上是真正的负载,如果我做对了,每个控件的每个请求都会触发一次。
另一种方法是不动态加载它。
在您的项目模板中,您可以使用以下内容:
<uc:MyControl runat="server
ChildItems='<%# ((MyClass) Container.DataItem).Children %>'
Visible='<%# ((MyClass) Container.DataItem).Children.Length > 0 %>'
/>
<强>更新强>
在转发器或页面生命周期内的用户控件中,从未给我带来子控件错误的另一种方法是使用Item Data Bound事件而不是Item Created。
实际上,当我现在考虑它时,你的代码不应该因为e.Item.DataItem还没有被绑定。
尝试将事件更改为ItemDataBound,看看是否有效。
我仍然建议你在项目标记中包含控件,并控制事件中控件的可见性(现在是ItemDataBound)。您可以通过e.Item.FindControl("ControlId") as MyControl
之类的内容来引用控件(如果在当前项中找不到则返回null)。
尝试将两者结合起来,或者至少将事件更改为数据绑定而不是创建,让我们看看......