为什么动态添加的用户控件的事件不会在回发上触发? [英] Why don't events of dynamically added user control fire on postback?

查看:176
本文介绍了为什么动态添加的用户控件的事件不会在回发上触发?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在SO上有很多类似的问题( 1 < ,a / >, 3 4 等),并在网络( 1 2 等),但没有相应的答案澄清我的情况。

There are plenty of similar questions on SO (1, 2, 3, 4 etc) and on the web (1, 2 etc) but none of the corresponding answers clarifies my situation.

我有一个简单的自定义用户控件,由两个下拉列表组成。在一个下拉列表中选择一个值应导致填充另一个值。只要我声明.aspx代码中的用户控件,一切都按预期工作。

I have a simple custom user control consisting of two drop-down lists. Selection of a value in one drop-down list should lead to the populating of the other one. As long as I declare the user control in the .aspx code everything works as expected.

现在我想以编程方式在页面上添加用户控件(按钮点击) 。虽然正在添加控件,但在一个下拉列表中的选择只会导致回发,但不会导致其他下拉列表的任何操作。

Now I want to add the user control on the page programmatically (on button click). Although the control is being added, the selection in one drop-down list causes only a postback but no action of the other drop-down list.

发现不仅 OnSelectedIndexChanged 不触发,而且 OnLoad 和所有其他事件。

While debugging I've found out that not only OnSelectedIndexChanged does not fire, but also OnLoad and all the other events.

所有讨论的常见原因如下:

Common reasons for such a behaviour regarding all the discussions I've looked through are the following:


  1. DropDownList 的AutoPostBack 未设置为true或数据绑定 DropDownList 在每次回发后都会反弹,导致事件的丢失。 //不是这种情况,更有可能是动态添加的下拉列表

  1. AutoPostBack of the DropDownList is not set to true or the databound DropDownList is being rebound on each postback which causes the losing of events. //not a case here, more likely refers to dynamically added drop-down lists

ID 分配给动态添加的控件在每个回发上自动(并且每次不同的一个,以便 ViewState 没有保持正确,事件不知道他们应该触发)。 //确定我已经检查了,现在手动分配ID

ID is assigned to the dynamically added control automatically on each postback (and every time a different one so that ViewState is not persisted correctly and events do not know that they should fire). // ok I've checked it and now assign the ID manually

控件只添加一次(而不是每个回发上添加一个必要的因为在 ViewState 中,只存储服务器控件的状态(值),而不是控件本身)和/或

The control is added only once (as opposed to the addition on every postback which is necessary because in the ViewState only the state (values) of server controls are stored, but not the controls themselves) and/or

控件是在每个回发上添加的,但在页面生命周期中却太晚了。 // ok我现在在 OnInit 事件处理程序中添加我的控件

the control is added on each postback but too late in the Page Life Cycle. //ok I'm adding my control in OnInit event handler now

为了让页面知道控件被添加(并且有多少个)我使用 Session 。下面一点代码,然后最后的问题:)

In order to let the page know that the control was added (and how many of them) I use Session. Below a bit of code and then finally the question :)

.aspx:

<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
    <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
    <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
</asp:Content>

和代码背后:

protected void Page_Load(object sender, EventArgs e)
        {
            if(!this.IsPostBack)
            {
            Session.Remove("Childcontrols");
            }
        }

        private void AddTransitControl()
        {
            List<Control> controls = (List<Control>)Session["Childcontrols"];
            AddTransitPoint atp = (AddTransitPoint)LoadControl("~/UserControls/AddTransitPoint.ascx");
            string id = this.ID + "_eb" + (controls.Count).ToString();
            atp.ID = id;
            controls.Add(atp);

            PlaceHolder1.Controls.Add(atp);
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if (Page.IsPostBack)
            {
                if (Session["Childcontrols"] == null)
                {
                    Session["Childcontrols"] = new List<Control>();
                }

                List<Control> controls = (List<Control>)Session["Childcontrols"];
                int count = 0;
                foreach (Control c in controls)
                {
//                    AddTransitPoint atp = (AddTransitPoint) c; //mystically not working (fires no events)
                    AddTransitPoint atp = (AddTransitPoint)LoadControl("~/UserControls/AddTransitPoint.ascx"); //it is working!

                    string id = this.ID + "_eb" + count;
                    count++;
                    atp.ID = id;
                    PlaceHolder1.Controls.Add(atp);
                }
            }
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            AddTransitControl();
        }

(我很确定用户控件本身的代码不是真正相关的情况,但根据要求,我可以稍后添加)。

(I'm pretty sure that the code of the user control itself is not really relevant for the case but on request I can add it later).

所以现在的问题:通过尝试和错误我发现,如果我存储新在 Session OnInit 中的集合中添加控件只需将控件从该集合中重新添加到控件集合我的占位符,没有这种控制的事件触发下一个回发(独立于回调的方式)。另一种方式,如果我创建 OnInit 一个新的控件存储在会话中并添加到这个新创建的控件的占位符控件集合 - 一切正常!那么存储在 Session 控件中的错误是什么,为什么他们失去了事件?

So now the question: Through trial and error I've found out that if I store the newly added control in the collection in Session and OnInit just take the control out of this collection and add again to the control collection of my placeholder, no events of this control fire on the next postback (independent of the way the postback is called). Other way if I create OnInit a new control for each stored in Session and add to the placeholder control collection this newly created control - everything works! So what is wrong with stored in the Session controls and why do they lose their events?

另外还有一个小问题在这里为此类控件创建ID的最佳做法是什么?我使用一串特殊的格式和一个柜台,但我怀疑这是最好的方法。例如,如果我添加了不同类型的控件,我将遇到这种方法的麻烦。

And one more small question here. What is the best practice for creating IDs for such controls? I use a string of particular format along with a counter, but I doubt it is the best way to do it. For example if I added different types of controls I would face trouble with this method.

感谢大家阅读这么长的问题,为您的宝贵意见!

Thank you everybody for reading such a long question and for your valuable input!

推荐答案

我的理解是:每次回发都必须重新建立事件。如果在ASPX文件中定义了事件,则可以免费获取此消息,因为在实例化页面对象时,会重新处理这些属性(OnClick,OnSelectionChanged等)。

My understanding is this: events must be re-established on every postback. You get this for free if the event is defined in the the ASPX file, because those attributes (OnClick, OnSelectionChanged, etc.) are re-processed when the page object is instantiated.

您不需要使用动态构建的控件或ASPX文件中定义的控件,而是将其事件与代码隔离。对于这些控件,事件在实例化时并不知道,因此页面不能自动为您重新建立。对于这些控件,您必须在每个回发中重新建立事件。

You do not get this for free with dynamically-built controls, or controls which are defined in the ASPX file but have their events wired-up in the codebehind. For those controls, the events are not known at instantiation time, thus the page can not automatically re-establish them for you. For those controls, you must re-establish your events on every postback.

我对会话存储数据的理解是:当您将对象放在会话中时,该对象本身并没有在记忆中活着。相反,它被序列化,并且序列化数据存储在会话中。当对象退出会话时,它将被反序列化。

My understanding of session-stored data is: when you put an object in the session, that object itself is not kept alive in memory. Instead, it is serialized, and the serialized data is stored in the session. When you get the object back out of the session, it is deserialized.

对象的事件在序列化/反序列化往返中无法生存,因为它们是逻辑函数指针 - 所以当对象被从内存中删除并稍后重新构建时,整个内存景观已经改变,所以这些事件/指针将不再有效。

Objects' events do not survive the serialization/deserialization round-trip because they are logically function pointers - so when the object is removed from memory and later re-built, the entire memory "landscape" has changed, so those events/pointers would no longer be valid.

I没有使用动态生成的控件进行大量的工作,所以我无法告诉你最有效的管理模式和事件。但是我知道,将它们存储在会话中并不是真正为每个回发重新创建它们带来的好处;并且不必要地使会话存储器膨胀。希望这个线程上的其他一些SOE可以指出你们最好的管理方式。

I haven't done a lot of work with dynamically-generated controls, so I can't tell you the most effective pattern to managing them and their events. But I know that storing them in the session isn't really buying you any benefit over re-creating them on each postback; and it is bloating up the session memory unnecessarily. Hopefully some other SO'ers on this thread can point you to the best-practices way of managing them.

这篇关于为什么动态添加的用户控件的事件不会在回发上触发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆