【问题标题】:Dynamically Created Controls losing data after postback回发后动态创建的控件丢失数据
【发布时间】:2013-07-09 11:34:35
【问题描述】:

实际上,我在Pageload 上创建了1 个TextBox,并将TextBox 添加到Panel。 现在,我有一个LinkButton,比如Add Another

我在 TextBox 中输入文本,如果需要,我需要通过单击 Add Another LinkButton 创建新的 TextBox

实际上,我可以得到计数并重新创建TextBoxes。 但是,问题是,我在以前生成的Textboxes 中输入的文本丢失了。

任何人都可以给我一个解决方案吗?

protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            if (!IsPostBack)
            {
                for (int i = 0; i < 5; i++)
                {
                    TableRow row = new TableRow();
                    for (int j = 0; j < 5; j++)
                    {
                        TableCell cell = new TableCell();
                        TextBox tb = new TextBox();                        
                        tb.ID = "TextBoxRow_" + i + "Col_" + j;                        
                        cell.Controls.Add(tb);                        
                        row.Cells.Add(cell);
                    }                    
                    Table1.Rows.Add(row);
                }
            }
        }
        catch (Exception ex)
        {
            throw;
        }        
    }

这是一个示例代码,同样的代码写在Button_Click

 protected void ASPxButton1_Click(object sender, EventArgs e)
    {
 int k = Table1.Controls.Count;
}

我在Button_Click 上收到Count=0

【问题讨论】:

  • 你能给我们看一些代码吗?

标签: c# asp.net .net runtime


【解决方案1】:

动态生成的控件不保持状态。你必须自己维护它。您可以使用一些隐藏字段来保留控件的状态,这些字段将在服务器端用于提取状态。 Asp.net 使用隐藏字段来维护请求之间的状态,可以在源码中看到__VIEWSTATE

在 ASP.NET 页面中,视图状态表示页面的状态 它最后在服务器上处理。它用于构建调用上下文 并在同一页面的两个连续请求中保留值。经过 默认情况下,使用隐藏字段将状态持久保存在客户端上 添加到页面并在页面之前在服务器上恢复 请求被处理。视图状态与 页面本身,但不代表或包含任何信息 与客户端页面显示相关,Reference

【讨论】:

  • 自己使用时是这样,但是如果将动态创建的控件添加到 PlaceHolder(或替代的 WebControl),那么这将保持动态控件的状态。只要您在页面加载(或之前)以及回发时重新创建动态控件,状态信息就会被保留。
  • @Adil 你能看看我的问题stackoverflow.com/questions/55817451/…。我也有同样的问题
【解决方案2】:

当使用动态控件时,你必须记住它们只会存在到下一次 postback.ASP.NET 不会重新创建动态添加的控件。如果您需要多次重新创建控件,则应在 PageLoad 事件处理程序中执行控件创建(因为目前您只是第一次使用 Condition: !IsPostabck 创建 TextBox)。这还有一个额外的好处,就是允许您在动态控件中使用视图状态。即使视图状态通常在 Page.Load 事件之前恢复,如果您在 PageLoad 事件的处理程序中创建一个控件,ASP.NET 将应用它在 PageLoad 事件处理程序结束后拥有的任何视图状态信息。

所以,去掉条件:!IsPostback,这样每次页面加载时,TextBox控件也会被创建。您还将看到在 PageLoad 处理程序完成后保存的文本状态框。 [ 显然你没有禁用 ViewState !!! ]

例子:

protected void Page_Load(object sender, EventArgs e)
{

    TextBox txtBox = new TextBox();
    // Assign some text and an ID so you can retrieve it later. 

    txtBox.ID = "newButton";
    PlaceHolder1.Controls.Add(txtBox);

}

现在运行它之后,在文本框中输入任何内容,看看当您单击任何导致回发的按钮时会发生什么。文本框仍然保持其状态!!!

【讨论】:

  • 能否详细说明 ViewState 以及它如何影响动态控件?
  • 祝福你!很好的解决方案。
【解决方案3】:

实际上,我使用 Javascript 来完成我的任务。 它是这样的:

<form id="form1" runat="server" enctype="multipart/form-data" method="post">
        <span style="font-family: Arial">Click to add files</span>&nbsp;&nbsp;
        <input id="Button1" type="button" value="add" onclick="AddFileUpload()" />
        <br />
        <br />
        <div id="FileUploadContainer">
            <!--FileUpload Controls will be added here -->
        </div>
        <asp:HiddenField ID="HdFirst1" runat="server" Value="" />
        <br />
        <asp:Button ID="btnUpload" runat="server" Text="Upload" OnClick="btnUpload_Click" />
    </form>

脚本:

 <script type="text/javascript">
        var counter = 0;

        function AddFileUpload() {

            var div = document.createElement('DIV');
            div.innerHTML = '<input id="file' + counter + '"name = "file' + counter + '"type="text"/><input id="file' + counter + '" name = "file' + counter + '" type="file" /><input id="Button' + counter + '" type="button" value="Remove" onclick = "RemoveFileUpload(this)" />';

            document.getElementById("FileUploadContainer").appendChild(div);
            counter++;
        }
        function RemoveFileUpload(div) {
            document.getElementById("FileUploadContainer").removeChild(div.parentNode);
        }

        function mydetails(div) {
            var info;
            for (var i = 0; i < counter; i++) {
                var dd = document.getElementById('file' + i).value;
                info = info + "~" + dd;
            }
            document.getElementById('<%= HdFirst1.ClientID %>').value = info;
        }
    </script>

在 Upload_Click 按钮中:

for (int i = 0; i < Request.Files.Count; i++)
        {           
           string strname = HdFirst1.Value;
           string[] txtval = strname.Split('~');
            HttpPostedFile PostedFile = Request.Files[i];
            if (PostedFile.ContentLength > 0)
            {
                string FileName = System.IO.Path.GetFileName(PostedFile.FileName);
               // string textname=
                //PostedFile.SaveAs(Server.MapPath("Files\\") + FileName);
            }
        }

【讨论】:

  • 永远不要将上传的文件保存在这样的普通目录中。例如,不良用户可能会上传一个 aspx 文件并...
【解决方案4】:

只需在每次回发期间在页面加载事件之前或之内重新实例化/重新初始化动态控件,然后将此控件添加到页面/表单/占位符。然后,通过父控件调用LoadPostData方法,将发布的数据自动分配给控件。

查看文章以及如何编写动态控制代码 - How to maintain dynamic control events, data during postback in asp.net

【讨论】:

  • 现在我对动态控制状态管理很清楚了,谢谢 vivek。
  • +1 获取详细的支持文章。对于回发/事件的动态控件的下划线工作,这是一个很好的参考。
【解决方案5】:

这是我在使用动态控件进行大量工作后的最终答案

.aspx

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div style="text-align: center">
    <div style="background-color: Aqua; width: 250px;">
    <br />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:PlaceHolder runat="server" ID="myPlaceHolder"></asp:PlaceHolder>
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="btnAddTextBox" EventName="Click" />
        </Triggers>
    </asp:UpdatePanel>
    <br />
    </div>
    <br />
    <asp:Button ID="btnAddTextBox" runat="server"  Text="Add TextBox" OnClick="btnAddTextBox_Click" />
    <br /><br />
    <asp:UpdatePanel ID="UpdatePanel2" runat="server">
        <ContentTemplate>
            <asp:Button runat="server" ID="MyButton" Text="Get Values." OnClick="MyButton_Click" />
            <br /><br />
            <asp:Label runat="server" ID="MyLabel"></asp:Label>
        </ContentTemplate>
    </asp:UpdatePanel>
 </div>
</form>

.aspx.cs

static int myCount = 0;
    private TextBox[] dynamicTextBoxes;

    protected void Page_PreInit(object sender, EventArgs e)
    {
        Control myControl = GetPostBackControl(this.Page);

        if ((myControl != null))
        {
            if ((myControl.ClientID.ToString() == "btnAddTextBox"))
            {
                myCount = myCount + 1;
            }
        }
    }

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        dynamicTextBoxes = new TextBox[myCount];
        int i;
        for (i = 0; i < myCount; i += 1)
        {
            TextBox textBox = new TextBox();
            textBox.ID = "myTextBox" + i.ToString();
            myPlaceHolder.Controls.Add(textBox);
            dynamicTextBoxes[i] = textBox;
            LiteralControl literalBreak = new LiteralControl("<br />");
            myPlaceHolder.Controls.Add(literalBreak);
        }
    }

    protected void btnAddTextBox_Click(object sender, EventArgs e)
    {
        // Handled in preInit due to event sequencing.
    }

    protected void MyButton_Click(object sender, EventArgs e)
    {
        MyLabel.Text = "";
        foreach (TextBox tb in dynamicTextBoxes)
        {
            MyLabel.Text += tb.Text + " :: ";
        }
    }

    public static Control GetPostBackControl(Page thePage)
    {
        Control myControl = null;
        string ctrlName = thePage.Request.Params.Get("__EVENTTARGET");
        if (((ctrlName != null) & (ctrlName != string.Empty)))
        {
            myControl = thePage.FindControl(ctrlName);
        }
        else
        {
            foreach (string Item in thePage.Request.Form)
            {
                Control c = thePage.FindControl(Item);
                if (((c) is System.Web.UI.WebControls.Button))
                {
                    myControl = c;
                }
            }
        }
        return myControl;
    }

【讨论】:

【解决方案6】:

删除这一行

 if (!IsPostBack)

【讨论】:

    【解决方案7】:

    当您使用动态控件时,它们将无法在回发期间维护其状态并且数据丢失,因为它们没有任何视图状态来维护其数据。

    您只需要将创建的控件数据维护到 ViewState 中 动态并在回发时将数据加载到页面中,您 完成。

    public Dictionary<Guid, string> UcList
    {
        get { return ViewState["MyUcIds"] != null ? (Dictionary<Guid, string>)ViewState["MyUcIds"] : new Dictionary<Guid, string>(); }
        set { ViewState["MyUcIds"] = value; }
    }
    
    public void InitializeUC()
    {
        int index = 1;
        foreach (var item in UcList)
        {
            var myUc = (UserControls_uc_MyUserControl)LoadControl("~/UserControls/uc_MyUserControl.ascx");
            myUc.ID = item.Value;
            pnlMyUC.Controls.AddAt(index, myUc);
            index++;
        }
    }
    
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadControl();
        else
            InitializeUC();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      • 2019-11-02
      • 2013-03-11
      • 1970-01-01
      相关资源
      最近更新 更多