将用户控件动态添加到转发器

时间:2011-10-05 23:14:46

标签: asp.net data-binding user-controls repeater

我有一个表示嵌套层次结构的类(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);
            }
        }
    }
}

2 个答案:

答案 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)。

尝试将两者结合起来,或者至少将事件更改为数据绑定而不是创建,让我们看看......