Как программно создать и использовать список флажков из ASP.NET?

У меня есть страница с таблицей материалов, и мне нужно разрешить пользователю выбирать строки для обработки. Я понял, как добавить столбец флажков в таблицу, но я не могу понять, как проверить, проверены ли они при отправке формы. Если бы они были статическими элементами, я мог бы просто проверить выполнение this.theCheckBox, но они генерируются программно.

Также я не очень доволен тем, как я прикрепляю к ним свои данные (вставляя их в свойство ID).

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


Редактировать: я нашел почти решение. Установив свойство AutoPostBack и событие CheckedChanged:

checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);

Я могу получить код, который будет вызываться в ответном сообщении для любого измененного флажка. Однако у этого есть две проблемы:

  • Обратный звонок обрабатывается после (или во время, я не уверен) Page_Load где мне нужно использовать эту информацию
  • Обратный вызов не вызывается для флажков, которые были отмечены при загрузке страницы и все еще установлены.

Редактировать 2:

В итоге я пометил все свои идентификаторы префиксом know и вставил это в начало Form_Load:

foreach (string v in this.Request.Form.AllKeys)
{
    if (v.StartsWith(Prefix))
    {
        var data = v.Substring(Prefix.Length);
    }
}

все остальное, кажется, запаздывает.


person BCS    schedule 24.07.2009    source источник


Ответы (7)


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

Код спереди:

<asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
    <ItemTemplate>
        <asp:CheckBox ID="DeleteMe" runat="server"/>
        <a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
            <%# DataBinder.Eval(Container, "DataItem.Title")%></a>
    </ItemTemplate>
</asp:DataList>
<asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>

Код позади:

public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadList();
    }

    protected void DeleteListItem_Click(object sender, EventArgs e)
    {
        foreach (DataListItem li in List.Items)
        {
            CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");

            if (delMe != null && delMe.Checked)
                    //Do Something
            }
        }

        LoadList();
    }

    protected void LoadList()
    {
        DataTable dt = //Something...
        List.DataSource = dt;
        List.DataBind();
    }

    protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
        {
            string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
            CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");

            if (delMe != null)
                delMe.Attributes.Add("value", id);                
        }
    }
}
person MyItchyChin    schedule 24.07.2009
comment
Как оказалось, я не использую ни одну из этих вещей. OTOH, мне нужно посмотреть, что делает ItemTemplate, так как это выглядит удобно. - person BCS; 25.07.2009

Во-первых, убедитесь, что у каждого флажка есть идентификатор и что в теге есть runat="server".

затем используйте функцию FindControl(), чтобы найти его.

Например, если вы перебираете все строки в GridView..

foreach(GridViewRow r in Gridview1.Rows)
{

    object cb = r.FindControl("MyCheckBoxId");
    if(r != null)
    {
      CheckBox chk = (CheckBox)cb;
      bool IsChecked = chk.Checked;
    }

}
person David    schedule 24.07.2009
comment
Я не могу найти, как установить runat. Я не могу просто отредактировать его в теге, так как все флажки генерируются внутри Form_Load через new CheckBox() - person BCS; 25.07.2009
comment
Поскольку элемент управления добавляется динамически и является элементом управления ASP, нет необходимости устанавливать атрибут runat. Как только вы правильно настроите все атрибуты для элемента управления и добавите к нему обработчики событий, он будет функционировать как любой другой элемент управления, добавленный во время разработки. Вы можете использовать метод FindControl @David, запустив цикл и создав идентификаторы, если вы знаете количество добавленных флажков, но это менее эффективно, чем прямой цикл через родительский контейнер при работе с несколькими элементами управления. - person Ahmad Mageed; 25.07.2009
comment
Я не проверял, но подозреваю, что он будет страдать от проблемы, связанной с тем, что он находит вещи только после того, как я их регенерировал, и мне это нужно раньше. - person BCS; 25.07.2009
comment
@BCS: Затем переместите свой код регенерации ИЛИ переместите код, который зависит от него, на более поздний этап жизненного цикла страницы. - person NotMe; 25.07.2009
comment
@Chris: Проблема с этой опцией заключается в том, что код, который мне нужно запустить в ответ на флажки, может изменить то, что должен создавать код регенерации. Если на то пошло, код регенерации может производить что-то другое из-за того, что другие сеансы меняют материал. - person BCS; 27.07.2009

Данные обратной передачи восстанавливаются между событием InitComplete и событием PreLoad. Если ваши флажки не созданы позже, флажки будут «догонять» свои события, и данные будут загружены в элемент управления вскоре после его создания.
Если для вас это слишком поздно, вам придется сделать что-то вроде того, что вы уже делаете. То есть вам нужно будет получить доступ к данным сообщения, прежде чем они будут переданы элементу управления.
Если вы можете сохранить UniqueId каждого созданного вами CheckBox, вы сможете напрямую получить доступ к данным сообщения, не присваивая им специальный префикс. Вы можете сделать это, создав список строк, в которых вы сохраняете идентификаторы по мере их создания, а затем сохраняете их в состоянии просмотра. Конечно, это требует, чтобы состояние представления было включено, и занимает больше места в состоянии представления.

foreach (string uniqueId in UniqueIds)
{
    bool data = Convert.ToBoolean(Request.Form[uniqueId]);
    //...
}
person drs9222    schedule 27.07.2009
comment
первый бит хорошо знать. Что касается бита UniqueId, я бы предпочел остаться без гражданства. - person BCS; 28.07.2009

Ваш пост немного расплывчатый. Было бы полезно увидеть, как вы добавляете элементы управления в таблицу. Это ASP:Table или обычная HTML-таблица (предположительно с атрибутом runat="server", поскольку вы успешно добавили в нее элементы)?

Если вы намерены позволить пользователю сделать несколько вариантов выбора, а затем нажать кнопку «Отправить», после чего вы будете обрабатывать каждую строку в зависимости от того, какая строка проверена, вам не следует обрабатывать событие CheckChanged. В противном случае, как вы заметили, вы будете каждый раз вызывать постбэк, и он не будет обрабатывать ни один из других флажков. Поэтому, когда вы создаете CheckBox, не устанавливайте обработчик событий, чтобы он не вызывал обратную передачу.

В обработчике событий вашей кнопки отправки вы должны пройти по каждой строке таблицы, ячейке, а затем определить, содержит ли дочерний элемент управления ячейки флажок.

Я бы посоветовал не использовать таблицу. Из того, что вы описываете, возможно, лучше использовать GridView или DataList.


EDIT: вот простой пример для демонстрации. Вы должны быть в состоянии заставить это работать в новом проекте для проверки.

Разметка

    <form id="form1" runat="server">
    <div>
    <table id="tbl" runat="server"></table>
    <asp:Button ID="btnSubmit" runat="server" Text="Submit"
      onclick="btnSubmit_Click" />
    </div>
    </form>

Код

protected void Page_Load(object sender, EventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        var row = new HtmlTableRow();
        var cell = new HtmlTableCell();
        cell.InnerText = "Row: " + i.ToString();
        row.Cells.Add(cell);
        cell = new HtmlTableCell();
        CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
        cell.Controls.Add(chk);
        row.Cells.Add(cell);
        tbl.Rows.Add(row);
    }
}

protected void btnSubmit_Click(object sender, EventArgs e)
{
    foreach (HtmlTableRow row in tbl.Rows)
    {
        foreach (HtmlTableCell cell in row.Cells)
        {
            foreach (Control c in cell.Controls)
            {
                if (c is CheckBox)
                {
                    // do your processing here
                    CheckBox chk = c as CheckBox;
                    if (chk.Checked)
                    {
                        Response.Write(chk.ID + " was checked <br />");
                    }
                }
            }
        }
    }
}
person Ahmad Mageed    schedule 24.07.2009
comment
Это HTML-таблица. Я хочу обрабатывать только проверенные строки, но CheckChanged для этого тоже не работает. после добавления asp:Button с обработчиком Click я обнаружил, что он также работает с опозданием (после Form_Load). Возможно, я делаю что-то не в том месте. - person BCS; 25.07.2009
comment
CheckChanged не будет запущен, так как вы установили для AutoPostBack значение false. Он должен быть установлен в значение true. Если вы не против отчитываться о каждом изменении чека, вы можете это сделать. В противном случае вы бы обработали их все сразу после нажатия кнопки отправки. В этом случае вы будете обрабатывать их в цикле, аналогичном тому, что я опубликовал. - person Ahmad Mageed; 25.07.2009
comment
Я добавил образец для демонстрации того, как это будет работать с учетом вашего сценария HTML-таблицы. - person Ahmad Mageed; 25.07.2009
comment
Когда я пробовал, CheckChanged запускается при отправке, если AutoPostBack=false. - person BCS; 27.07.2009
comment
Когда AutoPostBack имеет значение true, флажок будет отправлять обратно, когда вы изменяете его состояние. CheckChanged будет вызываться, если проверенное состояние изменится между обратными передачами. Не имеет значения, была ли обратная передача сгенерирована настройкой AutoPostBack, нажатием кнопки или чем-то еще, что создает обратную передачу. - person drs9222; 27.07.2009

Как насчет использования элемента управления CheckBoxList ? У меня сейчас нет открытой Visual Studio, но, насколько я помню, это элемент управления DataBound, предоставляющий DataSource и DataBind(), где вы можете предоставить список во время выполнения. Когда страница выполняет обратную передачу, вы можете просмотреть список, вызвав что-то вроде myCheckBoxList.Items, и проверить, выбран ли текущий элемент, вызвав метод ListItem.Selected. Это должно работать.

person Juri    schedule 27.07.2009
comment
Я никогда не использовал привязку даты, так что это недостаток. Еще одна проблема: вы случайно не знаете, может ли он обрабатывать данные до загрузки данных из DateSource? Это основано на данных, которые использовались для предыдущей загрузки страницы. - person BCS; 28.07.2009
comment
Думаю, я неправильно истолковал ваш вопрос. CheckBoxList не подходит для того, чего вы хотите достичь. Однако механизм DataBinding может вам помочь. Обрабатывайте материал до... ну, теоретически, вы просто загружаете свой элемент управления в случае !Page.isPostBack, поэтому ViewState снова сопоставит ваши предыдущие элементы с вашим элементом управления с привязкой к данным (Repeater, Grid или что-то еще). К сожалению, я не могу проверить это в данный момент, но должен быть способ получить флажки (также с помощью метода FindControl(...)). - person Juri; 28.07.2009

Добавьте их в переопределение метода CreateChildControls страницы. Обязательно дайте им удостоверение личности! Таким образом, они добавляются в дерево управления в нужное время.

ИМХО Лучшим способом было бы использовать DataBound Templateed Control, то есть что-то вроде ListView (в .NET 3.5). затем при загрузке страницы после обратной передачи пройдите по всем элементам в элементе управления с привязкой к данным и используйте item.FindControl, чтобы получить фактический флажок.

person Colin    schedule 27.07.2009
comment
Первый вариант не будет работать, так как мне нужно выполнить обработку, прежде чем создавать флажки, потому что обработка повлияет на то, какие флажки будут созданы. OTOH Мне придется изучить этот материал DataBound и посмотреть, как он работает. - person BCS; 28.07.2009

В итоге я пометил все свои идентификаторы префиксом know и вставил это в начало Form_Load:

foreach (string v in this.Request.Form.AllKeys)
{
    if (v.StartsWith(Prefix))
    {
        var data = v.Substring(Prefix.Length);
    }
}

все остальное, кажется, запаздывает.

person BCS    schedule 23.08.2009