Getting a DataRow from an ASP.NET GridView

2020-04-10 02:41发布

问题:

I have an ASP.NET GridView that's bound to an ObjectDataSource (which is bound to a MySQL database). On this grid, I have 2 unbound ButtonField columns that I want to trigger server-side events. Hence I have added an eventhandler method to the GridView's RowCommand event.

In the code of said eventhandler, I need to somehow get hold of the underlying DataRow that was clicked on by the user. However, I can't seem to get this to work; if I use code like the following the selectedRow variable is always null:

protected void searchResultsGridView_RowCommand(object sender, GridViewCommandEventArgs e)
{
  CallDataRow selectedRow = (CallDataRow) searchResultsGridView.Rows[Convert.ToInt32(e.CommandArgument)].DataItem;
}

I've Googled and found pages such as http://ranafaisal.wordpress.com/2008/03/31/how-to-get-the-current-row-in-gridview-row-command-event, but nothing I've found has worked. I'm pretty sure I'm just missing something obvious, but I can't figure out what...

Here's the ASP.NET code if that helps:

  <asp:GridView ID="searchResultsGridView" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="PersonNo,CallDate" 
    Width="100%" AllowPaging="True" EnableSortingAndPagingCallbacks="True" 
    onrowcommand="searchResultsGridView_RowCommand" PageSize="20">
    <Columns>
      <asp:BoundField DataField="PersonNo" HeaderText="Account number" ReadOnly="True" 
        SortExpression="PersonNo" />
      <asp:BoundField DataField="AgentNo" HeaderText="Agent number" 
        SortExpression="AgentNo" />
      <asp:BoundField DataField="AgentName" HeaderText="Agent name" 
        SortExpression="AgentName" />
      <asp:BoundField DataField="TelNumber" HeaderText="Telephone number" 
        SortExpression="TelNumber" />
      <asp:BoundField DataField="CallDate" HeaderText="Call date/time" ReadOnly="True" 
        SortExpression="CallDate" />
      <asp:ButtonField CommandName="play" HeaderText="Audio" ShowHeader="True" 
        Text="Play" />
      <asp:ButtonField CommandName="download" Text="Download" />
    </Columns>
  </asp:GridView>

回答1:

Finally got it to work by doing the following:

  1. Adding a TemplateField containing a bound HiddenField.

    <asp:TemplateField ShowHeader="False">
      <ItemTemplate>
        <asp:HiddenField ID="audioFileName" runat="server" Value='<%# Eval("AudioFileName") %>' />
      </ItemTemplate>
    </asp:TemplateField>
    
  2. Adding the following code in the RowCommand event handler:

    protected void searchResultsGridView_RowCommand(object sender, GridViewCommandEventArgs e)
    {
      string audioFile = ((HiddenField) searchResultsGridView.Rows[Convert.ToInt32(e.CommandArgument)].FindControl("audioFileName")).Value;
    }
    

It's a cludge and it's not particularly secure, but it works and that's all I need right now. Any better solutions are still welcome though...



回答2:

I'm even later to the party! But as I got here from Google, some people may still hit this hence I'll give my answer:

protected void SomeDataGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
   if (e.Row.RowType == DataControlRowType.DataRow)
   {
       System.Data.DataRowView dr = (System.Data.DataRowView)e.Row.DataItem;
       string aVar = dr["DataFieldIdLikePlease"].ToString();
   }
}

So then you get can get any of the data fields in the codebehind.



回答3:

I realize this is 2.5 years late (sorry! didn't see it before...), but I use two static/shared methods to convert the row directly. Maybe this is what you're looking to do?

VB.Net:

Public Shared Function GridViewRowToDataRow(ByVal gvr As GridViewRow) As DataRow
    Dim di As Object = Nothing
    Dim drv As DataRowView = Nothing
    Dim dr As DataRow = Nothing

    If gvr IsNot Nothing Then
        di = TryCast(gvr.DataItem, System.Object)
        If di IsNot Nothing Then
            drv = TryCast(di, System.Data.DataRowView)
            If drv IsNot Nothing Then
                dr = TryCast(drv.Row, System.Data.DataRow)
            End If
        End If
    End If

    Return dr
End Function

Public Shared Function GridViewRowEventArgsToDataRow(ByVal e As GridViewRowEventArgs) As DataRow
    Dim gvr As GridViewRow = Nothing
    Dim di As Object = Nothing
    Dim drv As DataRowView = Nothing
    Dim dr As DataRow = Nothing

    If e.Row.RowType = DataControlRowType.DataRow Then
        gvr = TryCast(e.Row, System.Web.UI.WebControls.GridViewRow)
        dr = Helpers.GridViewRowToDataRow(gvr)
    End If

    Return dr
End Function

C#.Net (Converted using: http://www.developerfusion.com/tools/convert/vb-to-csharp/):

public static DataRow GridViewRowToDataRow(GridViewRow gvr)
{
    object di = null;
    DataRowView drv = null;
    DataRow dr = null;

    if (gvr != null) {
        di = gvr.DataItem as System.Object;
        if (di != null) {
            drv = di as System.Data.DataRowView;
            if (drv != null) {
                dr = drv.Row as System.Data.DataRow;
            }
        }
    }

    return dr;
}

public static DataRow GridViewRowEventArgsToDataRow(GridViewRowEventArgs e)
{
    GridViewRow gvr = null;
    object di = null;
    DataRowView drv = null;
    DataRow dr = null;

    if (e.Row.RowType == DataControlRowType.DataRow) {
        gvr = e.Row as System.Web.UI.WebControls.GridViewRow;
        dr = Helpers.GridViewRowToDataRow(gvr);
    }

    return dr;
}


回答4:

 int index = Convert.ToInt32(e.CommandArgument);

 GridViewRow row = searchResultsGridView.Rows[index];


回答5:

A clean way to do this seems to be use the "DataKeyNames" property on the GridView. The datasource should contain a column which is a unique identifier or primary key. Then you can set the DataKeyNames property on the gridview to be the name of that property.

The value of that column corresponding to the selected row is then available in the RowCommand and it can be used to make sure the command is applied to the uniquely identified object

<asp:GridView ID="gridview" runat="server" ... DataKeyNames="pkey">


protected void gridview_OnRowCommand(object sender, EventArgs e)        
{
    string selectedPkey = null;
    GridViewCommandEventArgs  gridEvent = (GridViewCommandEventArgs)e;
    int index = Convert.ToInt32(gridEvent.CommandArgument);
    if (index >= 0 && index < gridview.Rows.Count)
    {
        GridViewRow r = gridview.Rows[index];
        selectedPkey = gridview.DataKeys[index].Value.ToString();
    }