skip to Main Content

I am struggling to get a datagrid working nicely for me. I realise there may be other controls that can do what I’m planning but i’m a way down the line with the datagrid so would like to see if this is possible. Essentially I have the following datagrid which is being bound to a SQL connection:

<asp:datagrid ID="dginventory" AutoGenerateColumns="false" runat="server" Width="99.4%" AllowPaging="True" AllowSorting="true" PageSize="20" OnPageIndexChanged="ChangePage" OnSortCommand="SortGrid" OnEditCommand="dginventory_oneditcommand" OnDeleteCommand="dginventory_ondeletecommand" >
            <HeaderStyle CssClass="datagridheader"/>
            <AlternatingItemStyle CssClass="datagridalternating"/>
            <ItemStyle cssClass="datagriditem"/>
            <Columns>
                <asp:BoundColumn DataField="PurchaseYear" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="YOP" ItemStyle-Width="4%" SortExpression="PurchaseYear ASC" />
                <asp:BoundColumn DataField="PurchaseDate" ItemStyle-HorizontalAlign="Center" HeaderText="Purchased" ItemStyle-Width="7%" DataFormatString="{0:d}" SortExpression="PurchaseDate ASC" />
                <asp:BoundColumn DataField="Number" HeaderText="Number" ItemStyle-Width="5%"  SortExpression="Number ASC" />
                <asp:BoundColumn DataField="Theme" HeaderText="Theme" ItemStyle-Width="10%" SortExpression="Theme ASC" />
                <asp:BoundColumn DataField="Name" HeaderText="Name" ItemStyle-Width="30%" SortExpression="Name ASC" />
                <asp:BoundColumn DataField="RRP" ItemStyle-HorizontalAlign="Left" HeaderText="RRP" ItemStyle-Width="4%" DataFormatString="{0:C}" />
                <asp:BoundColumn DataField="PurchasePrice" ItemStyle-HorizontalAlign="Left" HeaderText="Cost" ItemStyle-Width="4%" DataFormatString="{0:C}" />
                <asp:BoundColumn DataField="Discount" ItemStyle-HorizontalAlign="Left" HeaderText="Dis." ItemStyle-Width="4%" DataFormatString="{0:P1}" />
                <asp:BoundColumn DataField="ReleaseDate" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="Rel. Date" ItemStyle-Width="7%" DataFormatString="{0:d}" SortExpression="ReleaseDate ASC" />
                <asp:BoundColumn DataField="RetireDate" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="Ret. Date" ItemStyle-Width="7%" DataFormatString="{0:d}" SortExpression="RetireDate ASC" />
                <asp:BoundColumn DataField="Retailer" HeaderText="Retailer" ItemStyle-Width="10%" SortExpression="Retailer ASC" />
                <asp:BoundColumn DataField="StorageLocation" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="Box" ItemStyle-Width="3%" SortExpression="StorageLocation ASC" />
                <asp:TemplateColumn HeaderText="" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="Middle" HeaderStyle-HorizontalAlign="center" ItemStyle-Width="2%">
                    <ItemTemplate>
                        <asp:ImageButton src="Images/edit-alt-regular-24.png" ID="btneditset" alt="Edit" class="imagebutton" CommandName="Edit" runat="server" />
                    </ItemTemplate>
                </asp:TemplateColumn>
                <asp:TemplateColumn HeaderText="" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="Middle" HeaderStyle-HorizontalAlign="center" ItemStyle-Width="2%">
                    <ItemTemplate>
                        <asp:ImageButton src="Images/trash-regular-24.png" ID="btndeleteset" class="imagebutton" CommandName="Delete" runat="server"/>
                    </ItemTemplate>
                </asp:TemplateColumn>
            </Columns>
                <PagerStyle NextPageText="Next --&gt;" Font-Bold="True" PrevPageText="&amp;lt-- Prev" HorizontalAlign="Center" ForeColor="White" BackColor="Red" Mode="NumericPages" />
        </asp:datagrid>

As you can see I have two template columns, each containing an image. One for delete and one for Edit. I cannot seem to catch the click events of these image buttons no matter what I try. If I replace one of them with a ButtonColumn then that works fine however that means that I can’t use an image.

In the code behind I’ve setup these:

Sub dginventory_oneditcommand(ByVal sender As Object, ByVal e As DataGridCommandEventArgs)

    lblfilters.Text = "edit"

End Sub


Sub dginventory_ondeletecommand(ByVal sender As Object, ByVal e As DataGridCommandEventArgs)

    lblfilters.Text = "delete"

End Sub

Neither one of them seems to actually catch anything. I’ve also tried using onitemcommand which again doesn’t seem to fire. I did try adding an onclick to the two imagebuttons too but again no joy.

Hopefully I’ve described this well enough. I am using vb.net for the code behind in case that wasn’t clear.

Here’s hoping….

2

Answers


  1. Chosen as BEST ANSWER

    thank you for such an amazing response. I did try something similar to that, at one point yesterday, without much success. I have implemented your recommendation but it still doesn't seem to fire the event, or catch the right thing. I've only updated the delete button for now:

    <asp:datagrid ID="dginventory" AutoGenerateColumns="false" runat="server" Width="99.4%" AllowPaging="True" AllowSorting="true" PageSize="20" OnPageIndexChanged="ChangePage" OnSortCommand="SortGrid">
                <HeaderStyle CssClass="datagridheader"/>
                <AlternatingItemStyle CssClass="datagridalternating"/>
                <ItemStyle cssClass="datagriditem"/>
                <Columns>
                    <asp:BoundColumn DataField="PurchaseYear" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="YOP" ItemStyle-Width="4%" SortExpression="PurchaseYear ASC" />
                    <asp:BoundColumn DataField="PurchaseDate" ItemStyle-HorizontalAlign="Center" HeaderText="Purchased" ItemStyle-Width="7%" DataFormatString="{0:d}" SortExpression="PurchaseDate ASC" />
                    <asp:BoundColumn DataField="Number" HeaderText="Number" ItemStyle-Width="5%"  SortExpression="Number ASC" />
                    <asp:BoundColumn DataField="Theme" HeaderText="Theme" ItemStyle-Width="10%" SortExpression="Theme ASC" />
                    <asp:BoundColumn DataField="Name" HeaderText="Name" ItemStyle-Width="30%" SortExpression="Name ASC" />
                    <asp:BoundColumn DataField="RRP" ItemStyle-HorizontalAlign="Left" HeaderText="RRP" ItemStyle-Width="4%" DataFormatString="{0:C}" />
                    <asp:BoundColumn DataField="PurchasePrice" ItemStyle-HorizontalAlign="Left" HeaderText="Cost" ItemStyle-Width="4%" DataFormatString="{0:C}" />
                    <asp:BoundColumn DataField="Discount" ItemStyle-HorizontalAlign="Left" HeaderText="Dis." ItemStyle-Width="4%" DataFormatString="{0:P1}" />
                    <asp:BoundColumn DataField="ReleaseDate" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="Rel. Date" ItemStyle-Width="7%" DataFormatString="{0:d}" SortExpression="ReleaseDate ASC" />
                    <asp:BoundColumn DataField="RetireDate" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="Ret. Date" ItemStyle-Width="7%" DataFormatString="{0:d}" SortExpression="RetireDate ASC" />
                    <asp:BoundColumn DataField="Retailer" HeaderText="Retailer" ItemStyle-Width="10%" SortExpression="Retailer ASC" />
                    <asp:BoundColumn DataField="StorageLocation" ItemStyle-HorizontalAlign="Center" HeaderStyle-HorizontalAlign="center" HeaderText="Box" ItemStyle-Width="3%" SortExpression="StorageLocation ASC" />
                    <asp:TemplateColumn HeaderText="" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="Middle" HeaderStyle-HorizontalAlign="center" ItemStyle-Width="2%">
                        <ItemTemplate>
                            <asp:ImageButton ImageUrl="Images/edit-alt-regular-24.png" ID="btneditset" class="imagebutton" runat="server" />
                        </ItemTemplate>
                    </asp:TemplateColumn>
                    <asp:TemplateColumn HeaderText="" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="Middle" HeaderStyle-HorizontalAlign="center" ItemStyle-Width="2%">
                        <ItemTemplate>
                            <asp:ImageButton ImageUrl="Images/trash-regular-24.png" ID="btndeleteset" class="imagebutton" runat="server" CausesValidation="False" OnClick="btndeleteset_Click"/>
                        </ItemTemplate>
                    </asp:TemplateColumn>
                </Columns>
                    <PagerStyle NextPageText="Next --&gt;" Font-Bold="True" PrevPageText="&amp;lt-- Prev" HorizontalAlign="Center" ForeColor="White" BackColor="Red" Mode="NumericPages" />
            </asp:datagrid>
    

    Here is the code behind. For now it should just update a label on the form so that I can see something happening. I have also put a breakpoint on this the "lblfilters.Text =" line but that's not breaking either.

        Protected Sub btndeleteset_Click(sender As Object, e As ImageClickEventArgs)
        lblfilters.Text = "delete"
    End Sub
    

    Although it wasn't in your example I also dropped in the causevalidation = false to make sure I wasn't being hampered but that.

    Any ideas? Sorry


  2. Ok, the easiest way to do this when dropping in a button, ImageButton, or even a combo box for a row?

    Ignore the row command approach, and use a regular click event for the given control.

    The only "trick" here is that because the control is nested (in a repeater, Listview, GridView, DataGrid etc.), then you don’t have a property sheet for the given control, and thus can’t use the property sheet (or a double click) on the control to create the click event.

    However, you are 100% free to add, use and enjoy a click event by typing in markup directly. (and intel-sense will still help you).

    I should also point out that a DataGrid is the perhaps the oldest control, and in fact you often not see DataGrid in the tool box.

    So, I suggest in most cases to use a GridView. (they are very similar).

    And if you "grid" of data has more then a few custom controls, then I suggest using a ListView, as it is far more markup friendly. No worry, and using DataGrid is still ok despite being an older control.

    So, so say we have a simple DataGrid like this:

    (and note the 2 image buttons).

    So, then this:

      <asp:DataGrid ID="GHotels" runat="server" AutoGenerateColumns="false"
         DataKeyField="ID" CssClass="table table-hover" Width="45%" >
    
          <Columns>
            <asp:BoundColumn HeaderText="First" DataField="FirstName" runat="server" />
            <asp:BoundColumn HeaderText="Last" DataField="LastName" runat="server" />
            <asp:BoundColumn HeaderText="City" DataField="City" runat="server" />
            <asp:BoundColumn HeaderText="HotelName" DataField="HotelName" runat="server" />
            <asp:BoundColumn HeaderText="Description" DataField="Description" runat="server" />
    
            <asp:TemplateColumn HeaderText="Edit">
                <ItemTemplate>
                    <asp:ImageButton ID="cmdEdit" runat="server"
                        ImageUrl="~/Content/edit2.png" Width="48"
                        />
                </ItemTemplate>
            </asp:TemplateColumn>
    
            <asp:TemplateColumn HeaderText="Delete">
                <ItemTemplate>
                    <asp:ImageButton ID="cmdDelete" runat="server"
                        ImageUrl="~/Content/trashcan1.png" width="48"
                        OnClick="cmdDelete_Click"
    
                        />
    
                </ItemTemplate>
            </asp:TemplateColumn>
    
          </Columns>
      </asp:DataGrid>
    

    And code to load the grid looks like this:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
        If IsPostBack = False Then
            LoadGrid()
        End If
    
    
    End Sub
    
    Sub LoadGrid()
    
        Dim strSQL As String =
            "SELECT * FROM tblHotelsA
            ORDER BY HotelName"
    
        GHotels.DataSource = MyRst(strSQL)
        GHotels.DataBind()
    
    End Sub
    

    And the result is this:

    enter image description here

    Ok, so let’s add a delete click event to the image delete button in above.

    So, it looks like this from the editor:

    enter image description here

    So, as above shows, we are allowed and can with ease use standard click events (or other events) for that given control. This means VERY little reason exists to bother with and trying to use the row command. And bonus is we thus have a separate click event for each control and they are not all mumbled up into one event with a bunch of case statements.

    In the code behind, we can then pick up the row information like this:

    Protected Sub cmdDelete_Click(sender As Object, e As ImageClickEventArgs)
    
        Dim cmdDel As ImageButton = sender
        Dim gRow As DataGridItem = cmdDel.NamingContainer
    
        Dim PK As Integer = GHotels.DataKeys(gRow.ItemIndex)
    
        Dim strSQL As String =
            "DELETE FROM tblHotelsA WHERE ID = @ID"
    
        Dim cmdSQL As New SqlCommand(strSQL)
        cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = PK
        ' MyRstPE(cmdSQL)
    
        Debug.Print($"Row index click = {gRow.ItemIndex}")
        Debug.Print($"Database PK for row = {PK}")
    
    End Sub
    

    In above, I show how you get the current row (DataGridItem).

    In above, I show how you get the database PK value.

    In above, I show how you get the row index.

    Note the use of "naming" container. This is supported for ALL data bound controls, and returns the current row item.

    So, when I click on a given row button, then I have this in the output/debug window:

    enter image description here

    So, you are free to use regular click events for controls placed in a GridView, ListView, DataGrid etc.

    And the above advice also extends to say dropping in a combo box, or other controls. Their events can also be used, but you have to "type in" the event setting directly into the markup since the control is nested, and thus no property sheet is available.

    And for completeness, it fast becomes tiring to type code over and over to pull a data table with supplied SQL, so I have some helper routines I used in above, and use throughout the application.

    Public Function MyRst(strSQL As String, ByVal Optional strCon As String = "") As DataTable
    
        If strCon = "" Then
            strCon = My.Settings.TEST4
        End If
    
        Dim rstData As New DataTable
        Using conn As New SqlConnection(strCon)
            Using cmdSQL As New SqlCommand(strSQL, conn)
                conn.Open()
                rstData.Load(cmdSQL.ExecuteReader)
                rstData.TableName = strSQL
            End Using
        End Using
        Return rstData
    End Function
    
    Public Function MyRstP(cmdSQL As SqlCommand, ByVal Optional strCon As String = "") As DataTable
    
        If strCon = "" Then
            strCon = My.Settings.TEST4
        End If
    
        Dim rstData As New DataTable
        Using conn As New SqlConnection(strCon)
            Using (cmdSQL)
                cmdSQL.Connection = conn
                conn.Open()
                rstData.Load(cmdSQL.ExecuteReader)
            End Using
        End Using
    
        Return rstData
    
    End Function
    
    Public Sub MyRstPE(cmdSQL As SqlCommand, ByVal Optional strCon As String = "")
    
        If strCon = "" Then
            strCon = My.Settings.TEST4
        End If
    
        Dim rstData As New DataTable
        Using conn As New SqlConnection(strCon)
            Using (cmdSQL)
                cmdSQL.Connection = conn
                conn.Open()
                cmdSQL.ExecuteNonQuery()
            End Using
        End Using
    
    End Sub
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search