ASP.net使用循环显示TextBox控件

tjvv9vkg  于 2023-10-21  发布在  .NET
关注(0)|答案(2)|浏览(141)

在aspx页面上,我添加了几个TextBox控件行,如下所示:

<asp:Panel ID="panel1" runat="server" Visible="true">
    <tr>
         <asp:TextBox ID="txt1" runat="server"</asp:TextBox>
         
         <asp:DropDownList ID="dd1" runat="server">
            <asp:ListItem></asp:ListItem>
            <asp:ListItem></asp:ListItem>
            <asp:ListItem></asp:ListItem>
         </asp:DropDownList>
    </tr>

    <tr>
         <asp:TextBox ID="txt2" runat="server" ></asp:TextBox>
         
         <asp:DropDownList ID="dd2" runat="server">
            <asp:ListItem></asp:ListItem>
            <asp:ListItem></asp:ListItem>
            <asp:ListItem></asp:ListItem>
         </asp:DropDownList>
    </tr>

    <tr>
         <asp:TextBox ID="txt3" runat="server"></asp:TextBox>
         
         <asp:DropDownList ID="dd3" runat="server">
            <asp:ListItem></asp:ListItem>
            <asp:ListItem></asp:ListItem>
            <asp:ListItem></asp:ListItem>
         </asp:DropDownList>
    </tr>
</asp:panel>

上面的代码工作正常,但是有几行这样的行,因此我想使用一个循环。
假设有50行,我想用一个循环来显示这些行。我只想显示文本字段不为空的那些行。

<%
    for (int i = 1; i < 50; i++) {

        string txtBox = "txt" + i.ToString();

        if (string.IsNullOrEmpty(txtBox.Text)) {
            //display
        }
    }
 %>

在上面的代码中,我在txtBox.Text处得到错误,因为txtBox是一个局部变量。我也试过这个:

TextBox txt = (TextBox)this.FindControl(txtBox);

这不会给予错误,但会返回null。
所以我的问题是,如何用循环来显示上面的控件,而不是逐个键入每个控件。

cqoc49vn

cqoc49vn1#

好吧,不管你有三个,还是三十个。
简单的问题是,你想让某件事“重复”。
我建议使用一个列表视图,或者使用一个“repeater”,重复一个标记块和列表视图。
但是,我必须考虑某种数据源将驱动这些数据,因此您需要从数据库的Angular 考虑解决方案。即使列表视图没有数据库,您仍然需要考虑数据集或数据理论。
这里没有解决的第二个问题是组合框或下拉列表。
我无法想象这50行的值是手工输入的。因此,选择值的列表当然也来自数据源。(或者至少是代码中的一些数据集)。
因此,考虑到上述情况,让我们使用一个重复器,并“重复”一个模板。
无论如何,请说出这个标记:

<asp:Repeater ID="Repeater1" runat="server" 
    OnItemDataBound="Repeater1_ItemDataBound">
    <ItemTemplate>

        <div style="width:30%">
            <h3><%# Eval("hText") %></h3>

            <asp:TextBox ID="txt1" runat="server"
                Text='<%# Eval("TboxText") %>' >
            </asp:TextBox>

            <asp:DropDownList ID="dHotels" runat="server"
                style= "width:120px;margin-left:5px"                        
                DataValueField="ID"
                DataTextField="HotelName">
            </asp:DropDownList>
            <br />
            <hr/>
        </div>

    </ItemTemplate>
</asp:Repeater>

因此,从上面的关键概念是,你列出你希望重复的“一件事”,然后简单地给中继器提供一个数据列表(甚至是一些类的列表)。
每一行组合框的数据源(列表)都设置了一次,我们在项目数据绑定事件上,根据该数据表设置组合框的选项。
因此,现在落后的代码可以集中精力构建数据源,而不是混乱标记。
那么,这段代码:

DataTable rstHotels = new DataTable();
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadData();
    }

    void LoadData()
    {
        // combo box data (same for each repeat)
        rstHotels = 
            General.MyRst("SELECT ID, HotelName FROM tblHotelsA ORDER BY HotelName");

        int NumRows = 7;   // number of repeat's

        DataTable dt = new DataTable();
        dt.Columns.Add("hText", typeof(string));
        dt.Columns.Add("TboxText", typeof(string));

        for (int i = 0; i < NumRows; i++)
        {
            DataRow dr = dt.NewRow();
            dr[0] = "Item Text" + i.ToString();
            dr[1] = "TextBox " + i.ToString();
            dt.Rows.Add(dr);
        }
        Repeater1.DataSource = dt;
        Repeater1.DataBind();   

    }

    protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if ((e.Item.ItemType == ListItemType.Item) ||
            (e.Item.ItemType == ListItemType.AlternatingItem))
        {
            DropDownList cboList = (DropDownList)e.Item.FindControl("dHotels");
            cboList.DataSource = rstHotels;
            cboList.DataBind();
            cboList.Items.Insert(0, new ListItem("Select hotel", ""));
        }
    }

因此,然后您的代码变成了数据操作,以及基于“列表”或“设置”的操作,您让中继器控件(或GridView或ListView)处理您发送到该中继器“类型”控件的“行”数据或信息的重复。虽然这个例子使用了一个“Repeater”控件,但是您还有很多其他的选择。
上述结果如下:

因此,来自其他代码环境的代码往往使用循环来向页面添加控件,但正如您所看到的,此SO发布所需的唯一循环代码是创建一个“假”数据源。
下拉列表控件和选项也是如此,它们可以是数据源驱动的,而不需要编写甚至使用循环。

编辑:用户想要一个“添加行按钮”

这再次说明了为什么数据操作应该仅仅是数据操作,而不是从标记的Angular 来思考。
不要尝试使用标记和UI作为某种数据库存储数据。因此,要有一个添加按钮,我们只需添加一小段代码来保存用户输入的数据。
所以,用add按钮说这个标记:

<h3>My Hotel Ratings list</h3>
<asp:Repeater ID="Repeater1" runat="server" 
    OnItemDataBound="Repeater1_ItemDataBound">
    <ItemTemplate>
        <div style="width:30%">
            <h3><%# Eval("hText") %></h3>

            <asp:TextBox ID="txt" runat="server"
                Text='<%# Eval("TboxText") %>' >
            </asp:TextBox>

            <asp:DropDownList ID="dHotels" runat="server"
                style= "width:245px;margin-left:5px"                        
                DataValueField="ID"
                DataTextField="HotelName">
            </asp:DropDownList>
            <br />
            <hr/>
        </div>
    </ItemTemplate>
</asp:Repeater>
<br />
<asp:Button ID="cmdAdd" runat="server" Text="Add"
    OnClick="cmdAdd_Click" CssClass="btn"/>
<br />
<asp:Button ID="cmdDone" runat="server" Text="Done"
    OnClick="cmdDone_Click" CssClass="btn"
    />

现在,我们的代码基本相同,但我们增加了一个额外的例程,将值持久化到我们的“对象”中。在本例中,我使用的是一个数据表,但它当然也可以是我们定义的一个类,然后我们使用List<My Class object>
我们的代码是这样的:

DataTable cboHotels = new DataTable(); // choices for combo box
    DataTable rstData = new DataTable();    // repeating row data
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            CreateTable();
            LoadData();
            Session["rstData"] = rstData;
        }
        else
        {
            rstData = (DataTable)Session["rstData"];
        }
    }

    void CreateTable()
    {
        rstData.Columns.Add("hText", typeof(string));
        rstData.Columns.Add("TboxText", typeof(string));
        rstData.Columns.Add("cboChoice", typeof(int));
    }

    void LoadData()
    {
        // combo box data (same for each repeat)
        cboHotels =
            General.MyRst("SELECT ID, HotelName FROM tblHotelsA ORDER BY HotelName");

        Repeater1.DataSource = rstData;
        Repeater1.DataBind();   
    }

    protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if ((e.Item.ItemType == ListItemType.Item) ||
            (e.Item.ItemType == ListItemType.AlternatingItem))
        {
            DropDownList cboList = (DropDownList)e.Item.FindControl("dHotels");
            cboList.DataSource = cboHotels;
            cboList.DataBind();
            cboList.Items.Insert(0, new ListItem("Select hotel", "0"));
            DataRowView gRowData = (DataRowView)e.Item.DataItem;
            cboList.Text = gRowData["cboChoice"].ToString();
        }
    }

    void MyPersit()
    {
        // allows persiting of data
        // send repeater items back to rstData
        foreach (RepeaterItem rItem in Repeater1.Items)
        {
            DataRow OneRow = rstData.Rows[rItem.ItemIndex];
            OneRow["TboxText"] = ((TextBox)rItem.FindControl("txt")).Text;
            OneRow["cboChoice"] = ((DropDownList)rItem.FindControl("dHotels")).SelectedItem.Value;
        }
    }

    protected void cmdAdd_Click(object sender, EventArgs e)
    {
        MyPersit(); // save any changes
        DataRow NewRow = rstData.NewRow();
        NewRow["hText"] = "Item " + (rstData.Rows.Count + 1).ToString();
        NewRow["cboChoice"] = 0;
        rstData.Rows.Add(NewRow);   
        LoadData(); 
    }

    protected void cmdDone_Click(object sender, EventArgs e)
    {
        // done, 
        MyPersit();

        // now process data
        foreach(DataRow OneRow in rstData.Rows)
        {
            Debug.Print(OneRow["TboxText"].ToString());
            Debug.Print(OneRow["cboChoice"].ToString());
            // etc. etc. etc.   
        }
    }

我的意思是,实际上,这些数据应该是数据库的一部分,因为我无法想象用户会输入所有这些数据,然后你不会保存这些数据,对吗?
但是,即使这些数据不保存为数据库?注意如何从数据操作方面来思考这个问题,并且只使用标记和UI进行显示。应该考虑数据操作的概念,并与代码的标记和显示部分保持100%的分离。
上述结果如下:

bweufnob

bweufnob2#

不能通过定义变量来访问文本框或其他控件的id。txtBox是一个变量,您可以将其视为文本框ID。为了解决这个问题,我认为您应该从一开始就完全使用后端来构建您的控件。在这种情况下,您可以在循环中设置它们的值。但是要读取它们的值,您可以将它们的值存储在cookie中,例如,然后读取它们。也可以使用JavaScript为它们赋值

相关问题