Динамическая сетка текстовых полей ASP.net

У меня есть 2 списка строк, и я хотел бы динамически создавать сетку текстовых полей:

List<string> X = {"A", "B", "C"};
List<string> Y = {"1", "2", "3", "4"};

          A     B     C
     1   TBX   TBX   TBX
     2   TBX   TBX   TBX
     3   TBX   TBX   TBX
     4   TBX   TBX   TBX

     [Button]

Когда я ввожу данные в текстовые поля и нажимаю кнопку, я хотел бы иметь возможность перебирать эти текстовые поля и определять координаты «X» и «Y», связанные с каждым текстовым полем.

Я, вероятно, могу понять, как динамически создавать эту сетку текстовых полей, но я думаю, что столкнусь с проблемами, когда буду публиковать данные. Как получить значения из динамически созданных текстовых полей после обратной передачи?

У меня не будет проблем с итерацией и фактической логикой, но я не могу понять, как получить данные в контейнер, чтобы их можно было повторить. Придется ли мне снова динамически создавать текстовые поля при чтении опубликованных данных? На что это похоже?


person Mark    schedule 02.07.2012    source источник
comment
Веб-формы. Это своего рода хак ввода данных для ввода трубчатых данных. Будут вещи с javascript, которые будут парсить.   -  person Mark    schedule 03.07.2012


Ответы (2)


Вот еще один подход. У вас может быть заполнитель на странице asp.net. В коде динамически создайте таблицу с динамическими текстовыми полями и вставьте ее внутрь заполнителя. В этом случае у вас есть контроль над идентификатором каждого текстового поля. При обратной отправке значения, введенные в текстовые поля, будут сохранены (поскольку идентификаторы определены, вы также можете выполнять манипуляции с javascript)

Вот aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DynamicControls.aspx.cs" Inherits="Test2.DynamicControls" %>

<!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">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PHDynamicTable" runat="server"></asp:PlaceHolder>
        <asp:Button runat="server" ID="btnSubmit" Text="Submit" 
            onclick="btnSubmit_Click" />
    </div>
    </form>
</body>
</html>

Код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Test2
{
    public partial class DynamicControls : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
            CreateTextBoxesInTable();
        }

        private void CreateTextBoxesInTable()
        {
            PHDynamicTable.Controls.Clear();

            List<string> X = new List<string>() { "A", "B", "C" };
            List<string> Y = new List<string>() { "1", "2", "3", "4" };

            Table table = new Table();
            table.ID = "dynamicTable";

            TableRow tr;
            foreach (string y in Y)
            {
                tr = new TableRow();

                foreach (string x in X)
                { 
                    TableCell tc = new TableCell();

                    TextBox textBox = new TextBox();
                    textBox.ID = "txt_" + x + y;
                    tc.Controls.Add(textBox);

                    tr.Cells.Add(tc);
                }

                table.Rows.Add(tr);
            }

            PHDynamicTable.Controls.Add(table);
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            if (PHDynamicTable.Controls.Count > 0)
            {
                Table dynamicTable = (Table)PHDynamicTable.FindControl("dynamicTable");
                if (dynamicTable != null)
                {
                    foreach (TableRow tr in dynamicTable.Rows)
                    {
                        foreach (TableCell tc in tr.Cells)
                        {
                            TextBox textBox = (TextBox)tc.Controls[0];
                            string text = textBox.Text;
                            //Do whatever you want with the control
                        }
                    }
                }
            }
        }
    }
}

Несколько скриншотов

экран ввода с данными

введите здесь описание изображения

при постбэке (отправить)

введите здесь описание изображения

после отправки

введите здесь описание изображения

person Prashanth Thurairatnam    schedule 03.07.2012
comment
Спасибо. Я в основном пошел по этому пути, но то, как вы это сделали, намного чище. - person Mark; 03.07.2012
comment
Я думал, что это выглядит идеально для того, что я делаю, но PHDynamicTable «ничего», если я вызываю CreateTextBoxesInTable из OnPreInit. Если я вызову его из Page_Load в предложении «Если не IsPostback», таблица исчезнет после того, как я нажму кнопку обновления. Мне нужно вникнуть в порядок событий загрузки страницы. Наверное ничего страшного. - person Resource; 15.05.2015
comment
@user910683 user910683 Вероятно, вы должны были это видеть; но опять же для справки: msdn.microsoft.com/en-us/library/ ms178472.aspx#lifecycle_events - person Prashanth Thurairatnam; 16.05.2015
comment
Спасибо, Прашант. Я посмотрел на это, и это помогло мне определить, что мне нужен OnPreLoad. Я использую VB.NET, а не C# (не по своему выбору!), поэтому мой код не совсем совпадает с приведенным кодом. Однако это прямой перевод, и я понимаю, что порядок событий жизненного цикла не зависит от используемого языка. - person Resource; 18.05.2015

Помимо проблем с удобством использования, я предполагаю, что вы используете веб-формы ASP.NET, а не ASP.NET MVC. В веб-формах это становится своего рода кошмаром. Вы, конечно, можете вложить два элемента управления. Источник данных одного элемента управления становится первым списком, а второй источник данных — вторым списком. Затем в шаблоне вторичного повторителя вы помещаете текстовое поле asp:. Однако идентификатор здесь, даже если он задан явно, на самом деле будет сгенерированным значением, поскольку повторитель — это то, что известно в веб-формах ASP.nET как контейнер именования; это означает, что значения идентификаторов будут изменены во время выполнения.

При обратной передаче вы можете выполнить итерацию по дереву управления родительского повторителя, чтобы найти дочерний повторитель. Затем в дочернем ретрансляторе вы можете перебирать элементы управления этого ретранслятора, чтобы найти свои текстовые поля. что-то типа:

<asp:Repeater>
    <itemtemplate>
        <asp:repeater>
            <itemtemplate>
                <asp:textbox />
            </itemtemplate>
        </asp:repeater>   
    </itemtemplate>
</asp:repeater>

Затем в коде позади, в Post Back [псевдокод]

foreach(Control c in myTopRepeater.Controls){
    if(c == RepeaterControl) //is of type repeater. again, pseudo code
    {
         foreach(Control subC in c)
         {
             if(subC == textBox)
             {
                 //Compare generated name, etc to my Lists

             }
         }
    }
}

Это может помочь прочитать об именах контейнеров. Вы можете получить предсказуемую настройку именования, но она не на 100% интуитивно понятна. http://www.4guysfromrolla.com/articles/031710-1.aspx

Удачи!

person Richthofen    schedule 03.07.2012
comment
Да, именно так я бы рекомендовал делать это в веб-формах. - person saille; 03.07.2012