skip to Main Content

A 508 Scan flagged the fact that we have identical id’s for buttons in gridviews, and I’m wondering how to get around this. For some of these buttons we can remove the id’s entirely and they don’t seem to affect functionality, but others actually do have back-end code that enables/disables them based on other factors. Here’s the front-end code:

<asp:TemplateField HeaderText="Accept" ItemStyle-HorizontalAlign="Center">
                                    <ItemTemplate>
                                        <asp:Button
                                            ID="btnAccept"
                                            runat="server"
                                            Text="Accept Data"
                                            CssClass="inherited"
                                            CommandName="AcceptData"
                                            CommandArgument="<%# ((GridViewRow) Container).RowIndex %>" />
                                    </ItemTemplate>
                                    <ItemStyle HorizontalAlign="Center"></ItemStyle>
                                </asp:TemplateField>

And here is some of the backend code that pertains to this button:

protected void gvDashboard_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        try
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                int rowIndex = e.Row.RowIndex;

                Button btnAccept = e.Row.FindControl(@"btnAccept") as Button;
                Button btnRemove = e.Row.FindControl(@"btnRemove") as Button;

                bool errors = (bool)gvDashboard.DataKeys[e.Row.RowIndex][@"Errors"];
                string fileType = (string)gvDashboard.DataKeys[e.Row.RowIndex][@"FileType"];
                string processingStatus = (string)gvDashboard.DataKeys[e.Row.RowIndex][@"ProcessingStatus"];
                bool accepted = (bool)gvDashboard.DataKeys[e.Row.RowIndex][@"Accepted"];

                int records = 0;
                if (gvDashboard.DataKeys[e.Row.RowIndex][@"Records"] is System.DBNull)
                {
                    int recordsColumnIndex = Utilities.GetColumnIndexByHeaderText(gvDashboard, @"Records");
                    e.Row.Cells[recordsColumnIndex].Text = @"0";
                }
                else
                {
                    records = (int)gvDashboard.DataKeys[e.Row.RowIndex][@"Records"];
                }

                
                if (fileType == @"CN" || fileType == @"CP")
                {
                    if ((DBNull.Value.Equals(gvDashboard.DataKeys[e.Row.RowIndex][@"ZipId"]))
                        || ((int)gvDashboard.DataKeys[e.Row.RowIndex][@"ZipId"] == 0))
                    {
                        // CN or CP did not come from a zip file
                        if ((accepted))
                        {                                
                            btnAccept.Enabled = false;                                
                            btnRemove.Enabled = false;
                        }
                    }
                    else
                    {
                        btnAccept.Enabled = false;
                        btnRemove.Enabled = false;
                    }
                }
                
                if (accepted || processingStatus == @"I" || processingStatus == @"N")
                {
                    btnAccept.Enabled = false;
                }
            }
        }
        catch (Exception ex)
        {
            DAL.ErrorLog(@"FilteredDashboard.gvDashboard_RowDataBound: Row: " + e.Row.RowIndex.ToString() + "  " + ex.Message);
        }
    }

Ideally I would like to be able to add on an autogenerated number onto the front-end ID, but then account for ID’s with the same initial string (like ‘btnAccept’ or ‘btnRemove’) regarless of their additional numeric suffixes. Is that possible at all?

2

Answers


  1. ASP.NET Webforms auto generates button IDs for each control, unless you set it to

     ClientIDMode="Static"
    

    If you’d like to make sure the IDs are unique, set

     ClientIDMode="AutoID" //this is the default setting for all webform controls, and autogenerates an ID
    

    So the issue is probably coming from somewhere else, you can check it yourselves in the inspector of your browser.

    Login or Signup to reply.
  2. as noted in answer by Zee – you can use find control with the one name for each row – however, each row control – including buttons DOES get its own id.

    This problem should not exist – and as a general rule never has been a issue. Each row of the GV will auto generate new id for each row of controls. However, while new "id" are generated, you can on the row data bind events use find control with the control name without issue.

    Also, you really don’t need to save/put in the row index for hte button command args. In fact, you can also get the database primary key – and NOT even display or have the PK displayed in each row.

    Assuming you have datakeys set (say to PK "id" column), then you can then use a simple button row click event for a button on the gv row.

    You can’t double click on the button to add the event (since it inside the GV), but you can use intel-sense like this:

    Just type in onclick= , and when you hit "=", the you get intel sense like this:

    enter image description here

    So, you can choose create new event.

    Now, in this plane jane button event you can

    Get any value or control of that row.
    Get the row index - no need to put in markup
    Get the row primary key database row ID - again no need to have in markup.
    

    So, the code behind the button can look like this:

        protected void Button1_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            GridViewRow gRow = btn.NamingContainer as GridViewRow;
    
            Debug.Print("Row index click = " + gRow.RowIndex);
            Debug.Print("Data base PK ID = " + GridView1.DataKeys[gRow.RowIndex]["ID"]);
            // And you are free to using gRow.FindControl, or even the cells collection
            // for non templated values.
            // eg: gRow.Cells[0].Text
    

    Output:

    Row index click = 3
    Data base PK ID = 11
    

    Note how I used datakeys setting. This is REALLY nice for security, since I don’t have to expose client side the database row PK id used. And note how I also picked up the current GV row index – again all without having to put or mess with that stuff in the actual gv row. So, you don’t even need to use command Argument either. And you don’t need to use commandName either. You ONLY need to set CommandName if you want the Gv selected index event to fire. (so, you might need it), but as a general rule, just drop in a plane jane button – wire up the event, and get the current row with "naming container" as I did. And then you get the GV row, and with that you have everything you need – including rowindex, and even use of datakeys as I pointed out.

    In fact, this means for the most part I don’t bother with the built in GV events – they are not worth your time in most cases.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search