Pass querystring parameter with NavigaterUrl in HyperLink inside a GridView
Scenario:
Say you have a databound control like Gridview, Repeater or ListView that contains a column with link (HyperLink) to another page. In most of the cases, you might want to pass a value to another page to know which row or item was clicked by the use. E.g. You have a page that displays Customer records in a GridView and you have a link, when clicked takes the user to another page, where you want to display detailed information of the customer record the user selected in the GridView.
There are different ways to do this. You can use any of these depending on your scenario. I would say all these are already documented but I am just putting it together.
Note: I will be taking example of GridView these concepts should work for other databound Controls like Repeater, DataList, Listview, etc. There might need little modifications though based on which control you are using. All different ways shown below might not work will all but atleast on of them should work. If you find any difficulty post your question on www.asp.net forums and a link to that question as a comment to this post. I will look into it and post back.
1-a: Using HyperLinkField of GridView
Below is the code with GridView bound to a SqlDataSource (SDS). The SDS fetches CustomerID, CompanyName and ContactName from Northwind database. There is a link, Details, clicking on which will take you to another page CustomeDetails.aspx which will display more details about that customer. For that we need at least a CustomerId, which we can pass it via querystring to customer details page. The code below uses HyperLinkField that will display Details link.
<ASP:GRIDVIEW id=GridView1 runat="server" autogeneratecolumns="False" datakeynames="CustomerID" datasourceid="SqlDataSource1">
<COLUMNS>
<ASP:HYPERLINKFIELD text="Detail" datanavigateurlfields="CustomerID" datanavigateurlformatstring="CustomerDetails.aspx?customerId={0}"></ASP:HYPERLINKFIELD>
<ASP:BOUNDFIELD datafield="CustomerID" headertext="CustomerID" readonly="True" sortexpression="CustomerID"></ASP:BOUNDFIELD>
<ASP:BOUNDFIELD datafield="CompanyName" headertext="CompanyName" sortexpression="CompanyName"></ASP:BOUNDFIELD>
<ASP:BOUNDFIELD datafield="ContactName" headertext="ContactName" sortexpression="ContactName"></ASP:BOUNDFIELD>
</COLUMNS>
</ASP:GRIDVIEW>
<ASP:SQLDATASOURCE id=SqlDataSource1 runat="server" connectionstring="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
selectcommand="SELECT [CustomerID], [CompanyName], [ContactName] FROM [Customers]">
</ASP:SQLDATASOURCE>
Points to Note:
a) DataNavigateUrlFields: This corresponds to the field whose value we want to pass it into the querystring. Here it is CustomerID which we want to pass it to querystring.
b) DataNavigateUrlFormatString:This is the format of your url that will be rendered with the link. So in our e.g.CustomerDetails.aspx?customerId={0}, {0} corresponds to the "first field" in DataNavigateUrlFields i.e. CustomerID. When I said - first field -, it means yes we can have more than one fields, and is discussed next.
1-b: Passing more than one Querystring parameter with HyperLinkField in GridView:
Now what if we want to pass more than one parameter to the querystring? We need to change the two fields discussed above. I the code below, I am passing CompanyName as well in the querystring.
<asp:hyperlinkfield text="Detail" datanavigateurlfields="CustomerID,CompanyName"datanavigateurlformatstring="CustomerDetails.aspx?customerId={0}&companyName={1}" />
Points to Note:
a) The order of fields in DataNavigateUrlFields matters. i.e. {0} refers to CustomerID because it is the first field and {1} means CompanyName here.
2-a: Set NavigateUrl property of HyperLink in TemplateField in Markup
If you want more granular control, you can use HyperLink control inside TemplateField column type instead of HypeLinkField. Then the code for HyperLink will look like below:
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="hlDetails1" Text="Details" runat="server"
NavigateUrl='<%# "CustomerDetails.aspx?customer=" + Eval("CustomerID") + "&CompanyName=" + Server.UrlEncode(Eval("CompanyName").ToString())%>' />
</ItemTemplate>
</asp:TemplateField>
Points to Note:
a) NavigateUrl: You will be using here the NavigateUrl property of HyperLink control and build it like a string.
b) Eval : Using Eval method to get the field values e.g. Eval("CustomerID"
c) Server.UrlEncode: If you think your field is going to have spaces or special characters then use that. e.g. here the CompanyName can have spaces.
2-b: Set NavigateUrl property of HyperLink by Calling method in code-behind:
In this case, say you don't want to have too much manipulation in your markup or want some dynamic way to get the pagename, here is one another way to set the NavigateUrl property of HyperLink Field. This is the method that should work with almost all DataBound controls i.e. GV,DataList, Repeater, DetailsView, ListView, etc.
<asp:TemplateField><ItemTemplate><asp:HyperLink id="hlDetails2" Text="Details" Runat="server"NavigateUrl='<%# GetUrl(Eval("CustomerID"),Eval("CompanyName"))%>' /></ItemTemplate></asp:TemplateField>public string GetUrl(object id, object companyname){//here you can do validation e.g. if companyname is not null or something
//Also you can do some customization based on your logged-in user
//You can get the Page location dynamically from say web.config
string url =
"~/CustomerDetails.aspx?customerid=" + id.ToString() + "&companyname=" +Server.UrlEncode(companyname.ToString());return url;
}
Points to Note:
a) NavigateUrl now calls GetUrl method in the code-behind. Our GetUrl method takes 2 parameters namely customerid and companyname which we want to pass as querystring parameter.
b) GetUrl being in the code-behind, you can use all sort of customization/validation basically anything you want to build your url.
2-c: Set NavigateUrl in RowDataBound event
In this method we will use RowDataBound event of GridView Control. Now if you want to use it with Repeater or ListView or other control, you will be using corresponding event for that control. e.g. For Repeater you will be using ItemDataBound control. Below is the code:
i) Add RowDataBound event to GV. So your markup will change like below(in C#).
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="CustomerID"DataSourceID="SqlDataSource1" onrowdatabound="GridView1_RowDataBound">......</asp:GridView>
ii) Add this to your code-behind:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink hl = (HyperLink)e.Row.FindControl("hlDetails2");
if (hl != null)
{
DataRowView drv = (DataRowView)e.Row.DataItem;
string id = drv["CustomerID"].ToString();
string companyname = drv["CompanyName"].ToString();
hl.NavigateUrl = "~/CustomerDetails.aspx?customerid=" + id.ToString() + "&companyname=" + Server.UrlEncode(companyname.ToString());
}
}
}
Points To Note:
a) As I said earlier this concept will work for other databound controls but will need to make sure you use right event and right properties.
Conclusion:
Hope one of these methods will come handy. There might be some errors or some other ways. Let me know if you find any and I will update this post accordingly.
Sorry for the code-formatting. It is giving me hard time. So I have used in half and not in other.
Update: Finally I think the code-formatting now looks better.
Update 9/9/2011: From the comment by wonjartran below let me point out that for using DataRowView, you will need to import System.Data namespace.
i.e. using System.Data (C#) / Imports System.Data (VB.NET)