简体   繁体   English

动态添加的ASP.NET控件未存储在ViewState中

[英]Dynamically added ASP.NET controls not being stored in ViewState

I have an application where I need to add multiple (and nested) controls to a PlaceHolder. 我有一个应用程序,需要在其中将多个(和嵌套的)控件添加到PlaceHolder中。 The user enters the number of 'weeks', and my application adds a RadSplitter (using the Telerik control set), along with the relevant panes/grids for the weeks. 用户输入“周”数,我的应用程序添加了RadSplitter(使用Telerik控件集)以及相关的窗格/网格。 I add these controls using code behind. 我使用后面的代码添加这些控件。

This works fine when first binding (when entering the number of weeks, and clicking Submit). 第一次绑定时(输入星期数,然后单击提交),此方法效果很好。 But I also need to enable drag and drop functionality between the controls, which causes a postback. 但是我还需要启用控件之间的拖放功能,这会导致回发。

It seems that the number of controls in my placeholder is always '0' on postback, so I'm guessing they are not being stored in the ViewState. 在回发时,占位符中的控件数量似乎始终为“ 0”,因此我猜测它们没有存储在ViewState中。 Rather than have to readd these on every postback, how can I ensure my controls are stored in the ViewState? 不必每次都读回这些内容,而是如何确保控件存储在ViewState中?

Here's some example code: 这是一些示例代码:

      protected void btnSubmit_Click(object sender, EventArgs e)
        {
            if (plcSplitter.Controls.Count > 0)
                plcSplitter.Controls.Remove(plcSplitter.Controls[0]);
            var splitter = new Telerik.Web.UI.RadSplitter();
            splitter.Width = Unit.Percentage(100);
            int noOfWeeks = int.Parse(txtNoOfWeeks.Text);
            DateTime dt = new DateTime(2012, 05, 13);
            for (int i = 0; i < noOfWeeks; i++)
            {
                var range = new Common.DateRange(dt.AddDays(-6),dt);
                var pane = new Telerik.Web.UI.RadPane();
                Label lbl = new Label();
                lbl.ID = "lblText";
                lbl.Text = range.To.ToShortDateString();
                pane.Controls.Add(lbl);
                var gv = AddGrid(i);
                pane.Controls.Add(gv);
                splitter.Items.Add(pane);

                var splitLine = new Telerik.Web.UI.RadSplitBar();
            splitter.Items.Add(splitLine);

                dt = dt.AddDays(-7);
            }
            plcSplitter.Controls.Add(splitter);
            splitter.DataBind();
}

Controls are not stored in the viewstate, only some of control properties can be stored in viewstate. 控件不存储在viewstate中,只有某些控件属性可以存储在viewstate中。 So, on postback you must create these labels again. 因此,在回发时,您必须再次创建这些标签。

Move that logic to create labels from btnSubmit_Click to separate method, call that method on button click and store data needed to recreate labels somewhere (maybe session), then on postback in OnInit method check for that stored data and if there is some labels create it at that event. 移动该逻辑以将btnSubmit_Click中的标签创建为单独的方法,在单击按钮时调用该方法,并在某处(可能是会话)存储需要重新创建标签的数据,然后在OnInit方法中回发时检查该存储的数据,并检查是否存在一些标签在那个事件。

Be sure to read this blog post about viewstate : 请务必阅读有关viewstate的博客文章:

http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx

and this about creating controls in runtime 这与在运行时创建控件有关

http://weblogs.asp.net/infinitiesloop/archive/2006/08/25/TRULY-Understanding-Dynamic-Controls-_2800_Part-1_2900_.aspx http://weblogs.asp.net/infinitiesloop/archive/2006/08/25/TRULY-Understanding-Dynamic-Controls-_2800_Part-1_2900_.aspx

You can store the data necessary to build your controls in the ViewState, but the really important part is that you make sure your controls are built before you try to access them. 您可以在ViewState中存储构建控件所需的数据,但真正重要的部分是在尝试访问控件之前,请确保已构建控件。

Here's a super basic example. 这是一个超级基本的例子。

    protected void Page_Load(object sender, EventArgs e)
    {
        BuildControl(GetLabelData());
    }

    private Tuple<string, string> GetLabelData()
    {
        if (Page.IsPostBack)
            return (Tuple<string, string>)ViewState["MyLabelData"];
        else
            return new Tuple<string, string>("lblTest", "Test");
    }

    private void BuildControl(Tuple<string, string> t)
    {
        Label l = new Label();
        l.ID = t.Item1;
        l.Text = t.Item2;
        ViewState["MyLabelData"] = t;
        plcSplitter.Controls.Add(l);
    }

    protected void bDoSomething_Click(object sender, EventArgs e)
    {
        Response.Write(String.Format("plcSplitter.Controls.Count:{0}", plcSplitter.Controls.Count));
    }

It's also very important to recognize that these controls are being built at the server and if they can be altered by the client you'll need to implement some mechanism of communication for the important bits of info so you can rebuild your controls and then apply any modifications from the client. 同样重要的是要认识到这些控件是在服务器上构建的,如果客户端可以对它们进行更改,则需要对重要信息实施某种通信机制,以便您可以重新构建控件,然后应用任何控件。来自客户的修改。

For example you are implementing a draggable control, on the client side when you drag you'll need to store the coordinates in a hidden control manually so that can be posted back to the server and you can have that info available when you're rebuilding the controls. 例如,您正在实现一个可拖动控件,在客户端上拖动时,您需要将坐标手动存储在一个隐藏控件中,以便可以将其发布回服务器,并且在重建时可以使用该信息控件。

I think the reason those controls are not stored in the ViewState is that they are being added to the page "too late", after the page ViewState is generated. 我认为这些控件未存储在ViewState中的原因是,它们在页面ViewState生成后被添加到页面“太迟了”。 Look at this post: 看这个帖子:

Last event in page that can still affect a page's viewstate 页面中的最后一个事件仍会影响页面的查看状态

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM