Вопрос

Note: I've updated the code for this question to make the example a bit clearer and leverages the sample code provided by Karl Anderson below. I am also open to other ways of getting what I need to accomplish finalized.

I'm in the process of creating a form which includes multiple check boxes that may or may not be leveraged for each request. I'm attempting to create a button below these checkboxes in the DetailsView grid that will only check (as opposed to a button that will check and uncheck) the boxes if the need to check them all arises. As you can see from the code below that there are multiple text boxes/BoundFields surrounding the checkboxes that hold various types of information for this form. The form without the added complexity of the 'check all checkboxes' button works without any issues on the frontend and when writing to the database.

Using the code below the current hurdle I'm facing is not only getting the button to only check all the checkboxes at once, but getting past this error when the page loads:

Cannot convert type 'System.Web.UI.WebControls.TableCell' to 'System.Web.UI.WebControls.CheckBox' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion

From my research into similar (but not exact) errors, I need to convert the checkboxes into some other form. I've never faced this scenario before and I'm pulling my hair out not only looking for educational references but some sort of pointer on how to resolve not only the conversion portion but accurate and current (within the last few years) references on how I can resolve the bigger issue of the button correctly checking all 19 checkboxes.

What am I doing wrong here and is this the correct way to get the results I want doe a DetailsView? I'd not only like to learn how to resolve this but also learn the theory/logic behind this challenge so I can learn it the right way.

aspx code.

(Note some cosmetic code for the details view has been omitted)


<%@ Page Title="Test Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="form2.aspx.cs" Inherits="form2" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="FeaturedContent" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:DetailsView ID="DetailsView" runat="server" AutoGenerateColumns="False" CellPadding="4" DataSourceID="SqlDataSource1" ForeColor="#333333" GridLines="None">
    <AlternatingRowStyle BackColor="White" />
    <insert asp cosmetic gobbledy gook here>
    <Fields>
        <asp:BoundField DataField="Field_1" HeaderText="Ticket Number" SortExpression="Field_1" />
        <asp:BoundField DataField="Field 2" HeaderText="Field 2" SortExpression="Field_2" />
        <asp:BoundField DataField="Field_3" HeaderText="Field 3" SortExpression="Field_3" />
        <asp:BoundField DataField="Field_4" HeaderText="Field 4" SortExpression="Field_4" />
        <asp:BoundField DataField="Field_5" HeaderText="Field 5" SortExpression="Field_5" />
        <asp:BoundField DataField="Field_6" HeaderText="Field 6" SortExpression="Field_6" />
        <asp:BoundField DataField="Field_7" HeaderText="Field 7" SortExpression="Field_7" />
        <asp:BoundField DataField="Field_8" HeaderText="Field 8" SortExpression="Field_8" />
        <asp:BoundField DataField="Field_9" HeaderText="Field 9" SortExpression="Field_9" />
        <asp:BoundField DataField="Field_10" HeaderText="Field 10" SortExpression="Field_10" />
        <asp:CheckBoxField DataField="Check_Box_1" HeaderText="Check Box 1" SortExpression="Check_Box_1" />
        <asp:CheckBoxField DataField="Check_Box_2" HeaderText="Check Box 2" SortExpression="Check_Box_2" />
        <asp:CheckBoxField DataField="Check_Box_3" HeaderText="Check Box 3" SortExpression="Check_Box_3" />
        <asp:CheckBoxField DataField="Check_Box_4" HeaderText="Check Box 4" SortExpression="Check_Box_4" />
        <asp:CheckBoxField DataField="Check_Box_5" HeaderText="Check Box 5" SortExpression="Check_Box_5" />
        <asp:CheckBoxField DataField="Check_Box_6" HeaderText="Check Box 6" SortExpression="Check_Box_6" />
        <asp:CheckBoxField DataField="Check_Box_7" HeaderText="Check Box 7" SortExpression="Check_Box_7" />
        <asp:CheckBoxField DataField="Check_Box_8" HeaderText="Check Box 8" SortExpression="Check_Box_8" />
        <asp:CheckBoxField DataField="Check_Box_9" HeaderText="Check Box 9" SortExpression="Check_Box_9" />
        <asp:CheckBoxField DataField="Check_Box_10" HeaderText="Check Box 10" SortExpression="Check_Box_10" />
        <asp:CheckBoxField DataField="Check_Box_11" HeaderText="Check Box 11" SortExpression="Check_Box_11" />
        <asp:CheckBoxField DataField="Check_Box_12" HeaderText="Check Box 12" SortExpression="Check_Box_12" />
        <asp:CheckBoxField DataField="Check_Box_13" HeaderText="Check Box 13" SortExpression="Check_Box_13" />
        <asp:CheckBoxField DataField="Check_Box_14" HeaderText="Check Box 14" SortExpression="Check_Box_14" />
        <asp:CheckBoxField DataField="Check_Box_15" HeaderText="Check Box 15" SortExpression="Check_Box_15" />
        <asp:CheckBoxField DataField="Check_Box_16" HeaderText="Check Box 16" SortExpression="Check_Box_16" />
        <asp:CheckBoxField DataField="Check_Box_17" HeaderText="Check Box 17" SortExpression="Check_Box_17" />
        <asp:CheckBoxField DataField="Check_Box_18" HeaderText="Check Box 18" SortExpression="Check_Box_18" />
        <asp:CheckBoxField DataField="Check_Box_19" HeaderText="Check Box 19" SortExpression="Check_Box_19" />


        <asp:ButtonField ButtonType="Button" CommandName="btnSelectAll" Text="Select/Check All Servers"


        <asp:BoundField DataField="Field_11" HeaderText="Field 11" SortExpression="Field_11" />
        <asp:BoundField DataField="Field_12" HeaderText="Field 12" SortExpression="Field_12" />
        <asp:BoundField DataField="Field_13" HeaderText="Field 13" SortExpression="Field_13" />

        <asp:CommandField ButtonType="Button" NewText="CreateRecord" ShowInsertButton="True" />
    </Fields>
    <more asp non essential cosmetic gobbledy gook>

        </asp:DetailsView>
        <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:test_form_connect %>" runat="server" InsertCommand="INSERT INTO [test].[detailsview_test_form] ([Field_1], [Field_2], [Field_3], [Field_4], [Field_5], [Field_6], [Field_7], [Field_8], [Field_9], [Field_10], [Check_Box_1], [Check_Box_2], [Check_Box_3], [Check_Box_4], [Check_Box_5], [Check_Box_6], [Check_Box_7], [Check_Box_8], [Check_Box_9], [Check_Box_10], [Check_Box_11], [Check_Box_12], [Check_Box_13], [Check_Box_14], [Check_Box_15], [Check_Box_16], [Check_Box_17], [Check_Box_18], [Check_Box_19], [Field_11], [Field_12], [Field_13]) VALUES (@Field_1, @Field_2, @Field_3, @Field_4, @Field_5, @Field_6, @Field_7, @Field_8, @Field_9, @Field_10, @Check_Box_1, @Check_Box_2, @Check_Box_3, @Check_Box_4, @Check_Box_5, @Check_Box_6, @Check_Box_7, @Check_Box_8, @Check_Box_9, @Check_Box_10, @Check_Box_11, @Check_Box_12, @Check_Box_13, @Check_Box_14, @Check_Box_15, @Check_Box_16, @Check_Box_17, @Check_Box_18, @Check_Box_19, @Field_11, @Field_12, @Field_13) ">

        <InsertParameters>
    <asp:Parameter Name="Field_1" />
    <asp:Parameter Name="Field_2" />
    <asp:Parameter Name="Field_3" />
    <asp:Parameter Name="Field_4" />
    <asp:Parameter Name="Field_5" />
    <asp:Parameter Name="Field_6" />
    <asp:Parameter Name="Field_7" />
    <asp:Parameter Name="Field_8" />
    <asp:Parameter Name="Field_9" />
    <asp:Parameter Name="Field_10" />
    <asp:Parameter Name="Check_Box_1" />
    <asp:Parameter Name="Check_Box_2" />
    <asp:Parameter Name="Check_Box_3" />
    <asp:Parameter Name="Check_Box_4" />
    <asp:Parameter Name="Check_Box_5" />
    <asp:Parameter Name="Check_Box_6" />
    <asp:Parameter Name="Check_Box_7" />
    <asp:Parameter Name="Check_Box_8" />
    <asp:Parameter Name="Check_Box_9" />
    <asp:Parameter Name="Check_Box_10" />
    <asp:Parameter Name="Check_Box_11" />
    <asp:Parameter Name="Check_Box_12" />
    <asp:Parameter Name="Check_Box_13" />
    <asp:Parameter Name="Check_Box_14" />
    <asp:Parameter Name="Check_Box_15" />
    <asp:Parameter Name="Check_Box_16" />
    <asp:Parameter Name="Check_Box_17" />
    <asp:Parameter Name="Check_Box_18" />
    <asp:Parameter Name="Check_Box_19" />
    <asp:Parameter Name="Field_11" />
    <asp:Parameter Name="Field_12" />
    <asp:Parameter Name="Field_13" />

            </InsertParameters>
            </asp:SqlDataSource>


</asp:Content>

.....and the cs code:

using System;
using System.Configuration;
using System.Collections;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

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

}

protected void DetailsView1_ItemCommand(Object sender, DetailsViewCommandEventArgs e)
{
    foreach (Details
        if (e.CommandName == "btnSelectAll")
        {
        DetailsViewRow row = DetailsView1.Rows[9];
        (row.Cells[10] as CheckBox).Checked = true; 
        DetailsViewRow row1 = DetailsView1.Rows[10];
        (row1.Cells[11] as CheckBox).Checked = true;
        DetailsViewRow row2 = DetailsView1.Rows[11];
        (row.Cells[12] as CheckBox).Checked = true;
        DetailsViewRow row3 = DetailsView1.Rows[12];
        (row.Cells[13] as CheckBox).Checked = true;
        DetailsViewRow row4 = DetailsView1.Rows[13];
        (row.Cells[14] as CheckBox).Checked = true;
        DetailsViewRow row5 = DetailsView1.Rows[14];
        (row.Cells[15] as CheckBox).Checked = true;
        DetailsViewRow row6 = DetailsView1.Rows[15];
        (row.Cells[16] as CheckBox).Checked = true;
        DetailsViewRow row7 = DetailsView1.Rows[16];
        (row.Cells[17] as CheckBox).Checked = true;
        DetailsViewRow row8 = DetailsView1.Rows[17];
        (row.Cells[18] as CheckBox).Checked = true;
        DetailsViewRow row9 = DetailsView1.Rows[18];
        (row.Cells[19] as CheckBox).Checked = true;
        DetailsViewRow row10 = DetailsView1.Rows[19];
        (row.Cells[20] as CheckBox).Checked = true;
        DetailsViewRow row11 = DetailsView1.Rows[20];
        (row.Cells[21] as CheckBox).Checked = true;
        DetailsViewRow row12 = DetailsView1.Rows[21];
        (row.Cells[22] as CheckBox).Checked = true;
        DetailsViewRow row13 = DetailsView1.Rows[22];
        (row.Cells[23] as CheckBox).Checked = true;
        DetailsViewRow row14 = DetailsView1.Rows[23];
        (row.Cells[24] as CheckBox).Checked = true;
        DetailsViewRow row15 = DetailsView1.Rows[24];
        (row.Cells[25] as CheckBox).Checked = true;
        DetailsViewRow row16 = DetailsView1.Rows[25];
        (row.Cells[26] as CheckBox).Checked = true;
        DetailsViewRow row17 = DetailsView1.Rows[26];
        (row.Cells[27] as CheckBox).Checked = true;
        DetailsViewRow row18 = DetailsView1.Rows[27];
        (row.Cells[28] as CheckBox).Checked = true;
        DetailsViewRow row19 = DetailsView1.Rows[28];
        (row.Cells[29] as CheckBox).Checked = true;



    }
}   
}
Это было полезно?

Решение

The reason you are getting "'System.Web.UI.WebControls.CheckBox' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion" is because you are trying to cast a Cell into a CheckBox.

Please note that I find the CheckBox control inside the Rows Cell's ControlCollection.

Below is tested sample code that works:

Form:

    <asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333" GridLines="None" OnItemCommand="DetailsView1_ItemCommand">
<AlternatingRowStyle BackColor="White" />
<Fields>
    <asp:ButtonField ButtonType="Button" CommandName="btnSelectAll" Text="Select/Check All Servers" />
    <asp:ButtonField ButtonType="Button" CommandName="btnEdit" Text="Edit" />
    <asp:ButtonField ButtonType="Button" CommandName="btnCancel" Text="Cancel" />
    <asp:ButtonField ButtonType="Button" CommandName="btnSave" Text="Save" />
    <asp:CommandField ButtonType="Button" NewText="CreateRecord" ShowInsertButton="True" />
</Fields>
</asp:DetailsView>

Code Behind:

    DataTable m_table = null;

    public DataTable table
    {
        get
        {
            if (ViewState["m_table"] != null)
                return (DataTable)ViewState["m_table"];
            else
                return null;
        }
        set
        {
            ViewState["m_table"] = value;
        }
    }


    public static T FindControl<T>(ControlCollection controls)
    {
        for (int i = 0; i < controls.Count; i++)
        {
            if (controls[i] is T)
                return (T)(object)controls[i];
        }

            return default(T);
    }


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            table = new DataTable();

            DataColumn col1 = new DataColumn("Field_1");
            DataColumn col11 = new DataColumn("Check_Box_1");
            DataColumn col12 = new DataColumn("Check_Box_2");
            DataColumn col13 = new DataColumn("Check_Box_3");

            col1.DataType = System.Type.GetType("System.String");
            col11.DataType = System.Type.GetType("System.Boolean");
            col12.DataType = System.Type.GetType("System.Boolean");
            col13.DataType = System.Type.GetType("System.Boolean");

            table.Columns.Add(col1);
            table.Columns.Add(col11);
            table.Columns.Add(col12);
            table.Columns.Add(col13);

            DataRow row = table.NewRow();
            row[col1] = "1";
            row[col11] = false;
            row[col12] = false;
            row[col13] = false;

            table.Rows.Add(row);

            DetailsView1.DataSource = table;
            DetailsView1.DataBind();
        }

    }

    protected void DetailsView1_ItemCommand(Object sender, DetailsViewCommandEventArgs e)
    {
        if (e.CommandName == "btnSelectAll")
        {
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                for (int i = 0; i < row.Cells.Count; i++)
                {
                    CheckBox cb = FindControl<CheckBox>(row.Cells[i].Controls);
                    if (cb != null)
                    {
                        cb.Checked = true;
                    }                        
                }                    
            }
        }
        if (e.CommandName == "btnSave")
        {
            int j = 0;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                for (int i = 0; i < row.Cells.Count; i++)
                {
                    TextBox tb = FindControl<TextBox>(row.Cells[i].Controls);
                    if (tb != null)
                    {
                        table.Rows[0][j] = tb.Text;
                    }

                    CheckBox cb = FindControl<CheckBox>(row.Cells[i].Controls);
                    if (cb != null)
                    {
                        table.Rows[0][j] = cb.Checked;
                    }
                }
                j++;
            }

            DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);
            DetailsView1.DataSource = table;
            DetailsView1.DataBind();
        }
        if (e.CommandName == "btnEdit")
        {
            DetailsView1.ChangeMode(DetailsViewMode.Edit);
            DetailsView1.DataSource = table;
            DetailsView1.DataBind();
        }
        if (e.CommandName == "btnCancel")
        {
            DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);
            DetailsView1.DataSource = table;
            DetailsView1.DataBind();
        }
    }

Другие советы

This is untested, but should work so try this:

protected void DetailsView1_ItemCommand(Object sender, DetailsViewCommandEventArgs e)
{
    // Use the CommandName property to determine which button
    // was clicked. 
    if (e.CommandName == "btnSelectAll")
    {
        // You may need to tweak this as I almost never use DetailsView, but the concept should work
        // Check the Apples checkbox
        // Apples is the first row (index 0) and second cell (index 1)
        DetailsViewRow row = DetailsView1.Rows[0];
        (row.Cells[1] as CheckBox).Checked = true;

        // Check the Oranges checkbox
        // Apples is the second row (index 1) and second cell (index 1)
        DetailsViewRow row = DetailsView1.Rows[1];
        (row.Cells[1] as CheckBox).Checked = true;

        // Keep moving through the rows...
    }

}

try using client side script as

$(".btnClass").click(function(){
$(".chkBoxClass").attr("checked", "checked");
});

where btnClass is the class for the button and chkBoxClass is the common class for the checkboxes.

If you set a breakpoint at code like row.Cells[0] and look at the Controls property (either in a Quick Watch window or one of the other debugging windows), you should be able to find your relevant CheckBoxes and figure out how to traverse down to them from each cell.

HOWEVER, this should strike you as a really bad idea. Your code is, right now, tightly coupled to the structure of the page. This is going to be very difficult for you to maintain going forward, and anyone else who works on this project is probably going to spend a very long time trying to figure this out. This code needs to be thrown out.

If you need to have this many fields on a form, consider separating these fields onto a separate page entirely, and actually create the fields separately on the page itself. You may be thinking that this will take more time for users, but honestly -- this form has 13 parameters and 19 CheckBoxes. That is a complicated form that requires some special care and attention.

Finally, the time you (and other developers) save while making improvements to this page and fixing bugs will pay the users back very quickly.

Based on Karl Anderson's answer:

protected void DetailsView1_ItemCommand(Object sender, DetailsViewCommandEventArgs e)
{
    if (e.CommandName == "btnSelectAll")
    {
        foreach (DetailsViewRow row in DetailsView1.Rows)
        {
            (row.Cells[1].Controls[0] as CheckBox).Checked = true;
        }
    }

}

Not sure if this fixes everything, but it needs to be pulled into a loop, and I believe Controls[0] will give a handle on the checkbox.

I would try:

protected void DetailsView1_ItemCommand(Object sender, DetailsViewCommandEventArgs e) {
  if (e.CommandName == "btnSelectAll") {
    var controls = new Stack<Control>();
    controls.Push(DetailsView1);
    while (controls.Count > 0) {
      var control = controls.Pop();
      var checkbox = control as CheckBox;
      if (checkbox != null) {
        checkbox.Checked = true;
      }
      foreach (Control childControl in control.Controls) {
        controls.Push(childControl);
      }
    }
  }
}

Recurrent walk trough child controls work even on different control types.

Okay, so all you need to do to access the check box is change this line:

(row.Cells[10] as CheckBox).Checked = true;

to this line:

(row.Cells[10].Controls[0] as CheckBox).Checked = true;

The TableCell holds a collection of controls that are actually used to render the UI. In the case of the CheckBoxField the first control in the collection is the CheckBox.

Now, to make this code a little more scalable, I might do this:

if (e.CommandName == "btnSelectAll")
{
    for (int i = 9; i < 29; i++)
    {
        DetailsViewRow row = DetailsView1.Rows[i];
        (row.Cells[i + 1].Controls[0] as CheckBox).Checked = true; 
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top