3

I have a gridview for which I programmatically set the datasource and databind it to a collection of objects. For each row that is created I then use different methods in the fields to extract the relevant information from the object like this one:

<asp:TemplateField HeaderText="Aliases">
<ItemTemplate>
<%# ( (MyItem)Container.DataItem).Aliases.ToString() %>
</ItemTemplate>
</asp:TemplateField>

My problem is that in the OnRowDeleting method I would preferably like to be able to access that DataItem using e g MyGridView.Rows[e.RowIndex].DataItem or in other way. But I can’t find how to configure the Gridview to retain the DataItem. Is it possible to access the DataItem used and how would I configure it to do it? If that’s not possible can I access the values that are bind by the methods? Or do I have to go with plan B and rewrite the datasource object collection to a datatable and then use datakeysnames?

NetMage
  • 26,163
  • 3
  • 34
  • 55
Teletha
  • 603
  • 1
  • 11
  • 21

3 Answers3

5

MyGridView.Rows[e.RowIndex].DataItem should generally work but I guess that you are probably relying the view-state for retaining grid data on post-backs. In such case, you will get the DataItem property as NULL.

Work-around can be to always re-bind the grid with actual data in each postback early in page life cycle (say page_load).

However, in your case, you can very well use DataKeyNames. Contrary to your belief, you don't need a DataTable for this property to work. For example, if your class has property named ItemId indicating the key for your object then you can use DataKeyNames="ItemId" in the markup and refer it in OnRowDeleting using Keys property of event arguments.

VinayC
  • 47,395
  • 5
  • 59
  • 72
  • ViewState isn't used, however other things are saved in Session state. To use the DataKeyNames the propertys must be serializable correct? – Teletha Aug 17 '11 at 10:27
  • @teletha, actual data key values are stored in control-state (or view-state) so yes-your key property type has to be `serializable`. But most often, your key properties will be combination of int, string, guid and those are already marked as serializable. – VinayC Aug 17 '11 at 10:43
  • I see! These key values, are they the propertys of the DataItem that is being bound or how do I set/get these? Can I e g give a name to a row in the ItemTemplete? – Teletha Aug 17 '11 at 11:22
  • @Teletha, assuming you are binding your grid with the collection of objects of type 'MyItem' and if this class has a property called 'ItemId' then you have to set `DataKeyNames="ItemId"` at gridview level then `Keys` property of `GridViewDeleteEventArgs` will have value of this property for the object bound to the row being deleted. – VinayC Aug 17 '11 at 12:10
  • From what I can tell `DataKeyNames` won't work for the same reason as `DataItem` - it is only available when the grid is `DataBound` during the life cycle, which is not on postback. – NetMage Jun 03 '21 at 22:19
0

According to MSDN:

"The DataItem property is only available during and after the RowDataBound event of a GridView control."

Therefore, access the DataItem in the RowDataBound event:

Lets say you bind a List(Of Vehicle) to the grid:

Dim vehicles As List(Of Vehicle) = Vehicle.GetAll()
gvVehicles.DataSource = vehicles
gvVehicles.DataBind()

In the RowDataBound event access the DataItem:

Protected Sub gvVehicles_RowDataBound(sender As Object, e As GridViewRowEventArgs)

    If e.Row.RowType = DataControlRowType.DataRow Then
       Dim veh As Vehicle = TryCast(e.Row.DataItem, Vehicle)
       If Not veh Is Nothing Then
            Dim chkBox As CheckBox = CType(e.Row.FindControl("chkSelect"), CheckBox)
                chkBox.Checked = True
       End If
    End If
End Sub
Atomic Star
  • 5,427
  • 4
  • 39
  • 48
0

I'm aware this is very dated question at this point - however, I've just run into a similar issue and none of these answers resolved the issue; so I figured I'd post an alternative solution. In my scenario, the issue was on the OnSelectedIndexChanged event. So, it should theoretically hold true for OnRowDeleting but not necessarily on OnRowDeleted (depending on where exactly in the process the row is deleted).

My solution was to simply add a HiddenField for the data that I didn't want to be visible in the GridView, for example:

        <asp:GridView ID="gvTutorGroups" runat="server" AutoGenerateColumns="False" DataSourceID="sqlTutorGroups" DataKeyNames="TTGP_Group_Code" AllowPaging="True" PageSize="8" EmptyDataText="You have no tutor groups to display." Style="margin: 0 auto; width: 870px;" OnRowDataBound="gvTutorGroups_RowDataBound" OnSelectedIndexChanged="gvTutorGroups_SelectedIndexChanged">
            <Columns>
                <asp:TemplateField >
                    <ItemTemplate>
                        <asp:HiddenField runat="server" ID="hfTTGPISN" Value="<%# Eval("TTGP_ISN") %>" />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="TTGP_Group_Code" HeaderText="TG Code" />
                <asp:BoundField DataField="PRPH_Title" HeaderText="Name" />
                <asp:BoundField DataField="TTGP_Start_Date" HeaderText="Start Date" DataFormatString="{0:d}" />
                <asp:BoundField DataField="TTGP_End_Date" HeaderText="End Date" DataFormatString="{0:d}" />
            </Columns>
        </asp:GridView>

Then I just used the FindControl method to access that field, like so:

protected void gvTutorGroups_SelectedIndexChanged(object sender, EventArgs e)
{
    foreach (GridViewRow row in gvTutorGroups.Rows)
    {
        if (row.RowIndex == gvTutorGroups.SelectedIndex)
        {
            row.CssClass = "rowSelected";

            DataRowView dataItem = (DataRowView)row.DataItem;
            HiddenField hfTGIsn = (HiddenField)this.Parent.FindControl("hfTGisn");
            hfTGIsn.Value = ((HiddenField)row.FindControl("hfTTGPISN")).Value;
        }
        else
        {
            row.CssClass = "";
        }
    }
}

It's not an ideal solution, but it works.

Andrew Corrigan
  • 1,017
  • 6
  • 23