动态向重复器添加用户控件

5
我有一个代表嵌套层次结构的类(MyClass),该类具有一个MyClass集合属性和一个标题属性。
为了在网页上显示它,我希望创建一个用户控件,其中包含一个重复器。 在项模板中,我会使用文字将标题属性显示出来,重复器的ItemCreated事件中,我会创建一个新的用户控件实例,并将其添加到重复器中当前项中。
我的问题是,当用户控件的Page_Load事件触发时,如果控件是动态添加的,则repMyClass重复器属性为空,即使我调用EnsureChildControls。我错过了什么吗?如果我创建一个重复器并将我的用户控件放置在项模板中,它可以正常工作。我不能让它以动态方式工作吗?
用户控件:
<%@ 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);
            }
        }
    }
}

你能否编辑一下这段内容,解释并且可能清理一下。我认为你在这个句子中可能只完成了一半的编辑?“我的问题是,在Page_Load事件首次加载动态添加的控件时,repNyClass重复器属性为空。” - chrismay
2个回答

3

很久以前,我曾经使用手风琴创建嵌套报告来完成这项工作。

在索引中,当您想要动态添加用户控件实例时:

// 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”时强制赋值,您可以将其设置为属性并以编程方式分配任何值。


问题是,我的用户控件有它自己的子控件(在这种情况下是一个重复器)。在用户控件的page_load事件中,重复器变量实际上是空的。我无法自己设置它,需要asp.net框架来设置。 - Jeremy
@Jeremy:当然可以。只需创建一个类型为repeater的属性。然后您可以访问它,实例化它,以及对其进行任何操作。请澄清一下 - 根据我的理解,您应该在UserControl中拥有一个公共属性,在UserControl的Page Load事件中,您应该使用该公共属性将数据绑定到repeater上。这正确吗? - vvohra87

0

你可以在控件中创建另一个构造函数,该构造函数接受你想要的属性,并在加载事件中使用它,然后将其传递给LoadControl()调用中当前空对象数组。

另一种方法是在属性的setter中触发逻辑,而不是在控件的Load事件中触发,因为这实际上是真正的加载,并且每个请求每个控件只会触发一次,如果我理解正确的话。

另一种方法是根本不动态加载它。

在你的项模板中,你可以有类似以下的内容:

<uc:MyControl runat="server 
    ChildItems='<%# ((MyClass) Container.DataItem).Children %>'
    Visible='<%# ((MyClass) Container.DataItem).Children.Length > 0 %>'
    />

更新

另一种方法是在重复器或页面生命周期中使用子控件中的用户控件而不会发生错误的方法是使用项数据绑定事件而不是项创建。

实际上,现在我想起来,你的代码不应该工作,因为 e.Item.DataItem 还没有被绑定。

尝试将事件更改为 ItemDataBound,看看是否有效。

.

我仍然建议您将控件包含在项标记中,并在事件(现在是ItemDataBound)中控制控件的可见性。您可以通过类似于e.Item.FindControl("ControlId") as MyControl的方式引用控件(如果在当前项中未找到,则返回null)。
尝试结合两者,或者至少将事件更改为数据绑定而不是创建,并让我们看看...

问题在于,我的用户控件有它自己的子控件(在这种情况下是重复器)。在用户控件的Page_Load事件中,重复器变量实际上是null。我无法自己设置它,需要使用asp.net框架。 - Jeremy
理论上来说,你不应该需要使用load方法,而是应该使用setter方法。另一个选择是在答案更新中,那个可能会解决问题。我认为问题出在所使用的事件上,这很有可能是问题的原因。 - Meligy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接