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

发布于 2024-12-08 02:15:50 字数 2188 浏览 3 评论 0原文

我有一个类(MyClass),它代表一个嵌套层次结构,因此该类有一个属性,它是 MyClass 的集合。 MyClass 还有一个 title 属性

为了在网页上显示它,我希望创建一个具有转发器的用户控件。在项目模板中,我将使用文字来显示标题属性,并且在转发器的 ItemCreated 事件中,我将创建用户控件的新实例,并将其添加到转发器中的当前项目中。

我的问题是,当用户控件中的 Page_Load 事件触发时,如果控件是动态添加的,即使我调用 EnsureChildControls,repMyClass 转发器属性也为空。我在这里错过了什么吗?如果我创建一个中继器并将我的 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);
            }
        }
    }
}

I have a class (MyClass) which represents a nested hierarchy, so the class has a property which is a collection of MyClass. MyClass also has a title property

To show it on a web page, I was hoping to create a user control which had a repeater. In the item template I would have literal to display the title property, and on the ItemCreated event of the repeater, I would create a new instance of the usercontrol, and add it into the current item in the repeater.

My problem is, when the Page_Load event in the usercontrol fires, if the control was dynamically added, the repMyClass repeater poroperty is null, even if I call EnsureChildControls. Am I missing something here? If I create a repeater and drop my userctonrol in the item template it works fine. My can't I get this to work dynamically?

User Control:

<%@ 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>

User Control Code:

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);
            }
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情栀口红 2024-12-15 02:15:50

我很久以前就已经这样做了,使用折叠式创建嵌套报告。

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

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

I had done this a long time ago for creating nested reports using Accordions.

In Index, when you want to dynamically add User Control instances:

// 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);
}

Note:
In the User Control, you must add the "ClassName" in the declaration tag

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="myTest" ClassName="myClass" %>

Also, any properties you wish to expose when creating instances dynamically, you declare them as follows:

public string title { get; set; }

So if you want to force a value when creating for "repMyClass" you can set it as a property and assign whatever value you want to it programmaticaly.

笙痞 2024-12-15 02:15:50

您可以在控件中创建另一个构造函数来获取所需的属性并在加载事件中使用它,然后在 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)。

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

You can make another constructor in the control that takes the property you want and use it in the load event, and then pass it in the currently empty object array in LoadControl() call.

Another approach is to fire the logic in the setter of the property instead of in the Load event of the control, since is essentially the real load here and fires once per request per control if I get it right.

Another approach is not to load it dynamically as all.

inside your item template you can have something like:

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

Update

One more approach that never gave me errors with child controls in user controls inside repeaters or page life cycle, is to use the Item Data Bound event instead of the Item Created.

Actually, when I think about it now, your code shouldn't because e.Item.DataItem hasn;t been bound to yet.

Try to change the event to ItemDataBound and see if this works.

.

I still though recommend you include the control in the item markup, and control the visibility of the control in the event (now to be ItemDataBound). You can refer to the control by something like e.Item.FindControl("ControlId") as MyControl (will return null if not found in current item).

Try combining both, or at least changing event to data bound instead of created, and let's see...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文