【问题标题】:Persistent dynamic control in ASP.NetASP.Net 中的持久动态控制
【发布时间】:2011-08-13 10:14:35
【问题描述】:
<asp:Button onclick="Some_event" Text="Add TextBox" ID="id1" runat="server" />
//once clicked:
<asp:TextBox ID="txt1" ......></asp:TextBox>
//when clicked again:
<asp:TextBox ID="txt1" ......></asp:TextBox>
<asp:TextBox ID="txt2" ......></asp:TextBox>
//and so on...

有没有办法创建动态控件,即使在回发之后也会持续存在?换句话说,当用户单击按钮时,将生成一个新的文本框,当再次单击时,第一个文本框将保留,而第二个文本框将生成。如何使用 asp.net 做到这一点?我知道如果我可以在 page_init 事件中创建控件,那么它们将持续存在,但我不知道是否可以在 page_init 发生之前处理按钮单击,因此必须有另一种方法。

【问题讨论】:

  • 控件必须在回发时重新创建。但是,有一些项目可以使这项任务自动化,例如DynamicControlPlaceholder(它会持续存在并稍后重新创建控件)。
  • 是的,我读过它,但我想学习这些东西 :)

标签: c# asp.net dynamic controls persistent


【解决方案1】:

是的,这是可能的。使用纯 ASP.NET(这似乎是您所要求的)的一种方法是记录您添加的 TextBox 控件的计数(将该值存储在 ViewState 中)并重新创建TextBox 控制 Page_Load 事件。当然,现在大多数人可能会使用 Javascript 或 jQuery 来处理这个任务客户端,但我整理了一个简单的示例来演示它如何与回发一起工作:

首页:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DynamicControls.aspx.cs" Inherits="MyAspnetApp.DynamicControls" EnableViewState="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"></head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="btnAddTextBox" runat="server" Text="Add" OnClick="btnAddTextBox_Click" />
        <asp:Button ID="btnWriteValues" runat="server" Text="Write" OnClick="btnWriteValues_Click" />
        <asp:PlaceHolder ID="phControls" runat="server" />
    </div>
    </form>
</body>
</html>

后面的代码:

using System;
using System.Web.UI.WebControls;

namespace MyAspnetApp
{
    public partial class DynamicControls : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //Recreate textbox controls
            if(Page.IsPostBack)
            {
                for (var i = 0; i < TextBoxCount; i++)
                    AddTextBox(i);
            }
        }

        private int TextBoxCount
        {
            get 
            {
                var count = ViewState["txtBoxCount"];
                return (count == null) ? 0 : (int) count;
            }
            set { ViewState["txtBoxCount"] = value; }
        }

        private void AddTextBox(int index)
        {
            var txt = new TextBox {ID = string.Concat("txtDynamic", index)};
            txt.Style.Add("display", "block");
            phControls.Controls.Add(txt);
        }

        protected void btnAddTextBox_Click(object sender, EventArgs e)
        {
            AddTextBox(TextBoxCount);
            TextBoxCount++;
        }

        protected void btnWriteValues_Click(object sender, EventArgs e)
        {
            foreach(var control in phControls.Controls)
            {
                var textBox = control as TextBox;
                if (textBox == null) continue;
                Response.Write(string.Concat(textBox.Text, "<br />"));
            }
        }
    }
}

由于您在每次回发时重新创建控件,因此输入到文本框中的值将在每个回发中保持不变。我添加了btnWriteValues_Click 以快速演示如何从文本框中读取值。

编辑
我更新了示例以添加一个包含文本框和删除按钮的面板。这里的诀窍是删除按钮不会删除容器面板,它只是使它不可见。这样做是为了使所有控件 ID 保持不变,因此输入的数据与每个 TextBox 保持一致。如果我们要完全删除 TextBox,删除 TextBox 之后的数据会在下一次回发时下移一个 TextBox(只是为了更清楚地解释这一点,如果我们有 txt1、txt2 和 txt3,并且我们删除了 txt2,在下一次回发时,我们将创建两个文本框,txt1 和 txt2,而 txt3 中的值将会丢失)。

public partial class DynamicControls : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.IsPostBack)
        {
            for (var i = 0; i < TextBoxCount; i++)
                AddTextBox(i);
        }
    }

    protected void btnAddTextBox_Click(object sender, EventArgs e)
    {
        AddTextBox(TextBoxCount);
        TextBoxCount++;
    }

    protected void btnWriteValues_Click(object sender, EventArgs e)
    {
        foreach(var control in phControls.Controls)
        {
            var panel = control as Panel;
            if (panel == null || !panel.Visible) continue;
            foreach (var control2 in panel.Controls)
            {
                var textBox = control2 as TextBox;
                if (textBox == null) continue;
                Response.Write(string.Concat(textBox.Text, "<br />"));
            }
        }
    }

    private int TextBoxCount
    {
        get 
        {
            var count = ViewState["txtBoxCount"];
            return (count == null) ? 0 : (int) count;
        }
        set { ViewState["txtBoxCount"] = value; }
    }

    private void AddTextBox(int index)
    {
        var panel = new Panel();
        panel.Controls.Add(new TextBox {ID = string.Concat("txtDynamic", index)});
        var btn = new Button { Text="Remove" };
        btn.Click += btnRemove_Click;
        panel.Controls.Add(btn);
        phControls.Controls.Add(panel);
    }

    private void btnRemove_Click(object sender, EventArgs e)
    {
        var btnRemove = sender as Button;
        if (btnRemove == null) return;
        btnRemove.Parent.Visible = false;
    }
}

【讨论】:

  • 如果我想删除动态文本框怎么办?每当创建文本框时,我都会插入一个按钮并为其分配一个事件。实际上,在第一次单击时,文本框已成功删除,但随后可能会出现一些错误(不是例外,例如单击时未保存教科书的值)。有没有简单的方法可以删除指定的文本框?
  • @Shaokan 我更新了我的答案,包括删除文本框。
  • 哈哈,这太容易了 :) 我一直在移除面板,再次感谢 :) 它现在可以正常工作了 :)
【解决方案2】:

我阅读了 Scott Mitchell 的一篇文章,其中解释了 ViewState 仅在回发过程中保持更改的控件状态,而不是实际控件本身。我没有您的确切情况,但是我正在处理的项目需要动态添加的用户控件,并且我必须在每次回发时添加它们。在这种情况下,在 Init 中创建它们仍然很有用,以便它们可以保留它们的状态。这是链接:Understanding ASP.NET View State。检查“查看状态和动态添加的控件”部分。

您可能必须跟踪您正在添加的所有控件(例如在会话状态中)并在回发时重新创建它们。我刚刚做了一个小测试,我在 Session 中保留了所有 Textbox id 的 List&lt;string&gt;。在回发时,我重新创建所有文本框。

【讨论】:

  • 非常感谢!我想我在度假的时候有很多东西要读:)
猜你喜欢
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-01
  • 2017-04-08
  • 1970-01-01
相关资源
最近更新 更多