Using DataKeyNames in the ASP.NET GridView control
Recently I was asked by a work colleague about what was the best way to hide primary keys when displaying data in a GridView control. I mentioned the DataKeyNames property and got a blank stare. This little gem is a property on the GridView control that allows you to set an array that contains the primary key fields for the items displayed in a GridView control.
Let’s get started. Open Visual Studio 2008 and create a new Web Application. This example won’t hook into a database, but we will create a class to mock a table and retrieve data from it instead. Right click on the project and choose Add > Class. Name the class Customer. Open the Customer class and add the following code:
C#
public class Customer
{
public int ID { get; set; }
public string GivenName { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public string NickName { get; set; }
}
VB.NET
Public Class Customer
Private privateID As Integer
Public Property ID() As Integer
Get
Return privateID
End Get
Set(ByVal value As Integer)
privateID = value
End Set
End Property
Private privateGivenName As String
Public Property GivenName() As String
Get
Return privateGivenName
End Get
Set(ByVal value As String)
privateGivenName = value
End Set
End Property
Private privateSurname As String
Public Property Surname() As String
Get
Return privateSurname
End Get
Set(ByVal value As String)
privateSurname = value
End Set
End Property
Private privateEmailAddress As String
Public Property EmailAddress() As String
Get
Return privateEmailAddress
End Get
Set(ByVal value As String)
privateEmailAddress = value
End Set
End Property
Private privateNickName As String
Public Property NickName() As String
Get
Return privateNickName
End Get
Set(ByVal value As String)
privateNickName = value
End Set
End Property
End Class
The Customer class contains five properties. The ID property is going to the unique identifier, so this is to be used internally by the application and should not be displayed to the user.
The next step is to create a collection of Customer objects and bind this to a GridView control. Open the Default.aspx page and the following code:
<asp:GridView ID="grdCustomer" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" onrowcommand="grdCustomer_RowCommand">
<Columns>
<asp:CommandField CausesValidation="false" ButtonType="Image" SelectImageUrl="~/Users.gif" ShowSelectButton="true" />
<asp:BoundField DataField="GivenName" HeaderText="Name" />
<asp:BoundField DataField="Surname" HeaderText="Surname" />
<asp:BoundField DataField="EmailAddress" HeaderText="Email" />
<asp:BoundField DataField="NickName" HeaderText="Nick Name" />
</Columns>
</asp:GridView>
In the code above the DataKeyNames property is set to the ID property. When data is bound to the GridView control, the GridView will look for a property named ID. When it is found, the value will be used as the primary key for each row in the GridView. This enables you to not display the ID to the user, yet still being able to retrieve it. You can also assign multiple primary keys if desired by separating them with a comma (,). For example you could have the following code:
DataKeyNames="ID,Surname"
This means that now there are two primary key values defined; ID and Surname. A CommandField was also created in the code above. The ButtonType is set to Image, so for each row that is created in the GridView, an image will be displayed to the user. Clicking the image will raise the RowCommand event on the GridView. The purpose of doing this is to show you how to retrieve the DataKey value from the GridView control.
The next step is to create a collection of Customer objects and bind that to the GridView control. Open the Default.aspx page and add the following code:
C#
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer()
{
ID = 123,
GivenName = "Steve",
Surname = "Jobs",
EmailAddress = "steve@apple.com",
NickName = "Steve"
});
customers.Add(new Customer()
{
ID = 789,
GivenName = "Bill",
Surname = "Gates",
EmailAddress = "bgates@microsoft.com",
NickName = "Bill"
});
grdCustomer.DataSource = customers;
grdCustomer.DataBind();
}
}
VB.NET
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
If (Not IsPostBack) Then
Dim customers As New List(Of Customer)()
customers.Add(New Customer() With {.ID = 123, .GivenName = "Steve", .Surname = "Jobs", .EmailAddress = "steve@apple.com", .NickName = "Steve"})
customers.Add(New Customer() With {.ID = 789, .GivenName = "Bill", .Surname = "Gates", .EmailAddress = "bgates@microsoft.com", .NickName = "Bill"})
grdCustomer.DataSource = customers
grdCustomer.DataBind()
End If
End Sub
In the code above, I have created a generic List<Customer> or List(Of Customer) to store the information. I have used a new feature to C# and VB.Net called Object Initialization. This allows you to create a new instance of a class and assign values to properties in one easy step. Finally the code is bound to the GridView control by calling the DataBind method.
The last piece of code is to create an event handler for the RowCommand event. Open the Default.aspx page in the Design view. Select the GridView. Open the properties and select the lightning bolt to view the events for the GridView:
Double click the RowCommand event and Visual Studio will automatically create the event handler. Add the following code:
C#
protected void grdCustomer_RowCommand(object sender, GridViewCommandEventArgs e)
{
object dataKeyValue = grdCustomer.DataKeys[int.Parse(e.CommandArgument.ToString())].Value;
}
VB.NET
Protected Sub grdCustomer_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs)
Dim dataKeyValue As Object = grdCustomer.DataKeys(Integer.Parse(e.CommandArgument.ToString())).Value
End Sub
When the user selects a record from the grid, the selected row index will be passed through as the CommandArgument. Run the project and place a breakpoint on the code above. Select a row. The program will stop on the breakpoint and you will be able to see the selected row index being passed through. You can then use the code below to retrieve the ID value:
The DataKeys property expects an integer. From there you can query the Value property to retrieve a single value, or you can query the Values property if you have an array of DataKeys defined.
Now that you have the primary key, you can go ahead and use it to lookup data from another table perhaps. DataKeyNames are a great way to use primary keys without having to display them to the user. If you have more than one primary key, you can separate the values with a comma. This adds extra flexibility to a great property.
The source code of this article in C# can be downloaded from here.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @
malcolmsheridan