Home > Software design >  Unique ID's for buttons in gridview?
Unique ID's for buttons in gridview?

Time:03-12

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?

CodePudding user response:

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.

CodePudding user response:

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.

  • Related