Monday, October 19, 2009

Selectable GridViewRow

1 comments
I have always found using Select Button in GridView to select a row cumbersome.
It would be always better to click anywhere on the GridViewRow and Select the row.

Here's a snippet on how to do it.

On RowDataBound

protected void gvwProducts_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{

e.Row.Attributes["onmouseover"] = "this.style.color='DodgerBlue';this.style.cursor='hand';";
e.Row.Attributes["onmouseout"] = "this.style.color='Black';";
e.Row.Attributes["onclick"] = ClientScript.GetPostBackClientHyperlink(this.gvwProducts, "Select$" + e.Row.RowIndex);
e.Row.ToolTip = "Click on the row to select it";
}
}


Now if we run the code and click on the row we will get this error



System.ArgumentException: Invalid postback or callback argument.
Event validation is enabled using in configuration
or <%@ Page EnableEventValidation="true" %> in a page.
For security purposes, this feature verifies that arguments to postback or callback events originate
from the server control that originally rendered them.
If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method
in order to register the postback or callback data for validation.



To avoid this we override the Page's Render Event.
Inside that event we register an event reference for validation on each GridViewRow

The overridden Page Render

protected override void Render(HtmlTextWriter writer)
{
// .NET will refuse to accept "unknown" postbacks for security reasons. 
// Because of this we have to register all possible callbacks
// This must be done in Render, hence the override
for (int i = 0; i < gvwProducts.Rows.Count; i++)
{
Page.ClientScript.RegisterForEventValidation(new System.Web.UI.PostBackOptions(gvwProducts, "Select$" + i.ToString()));
}
// Do the standard rendering stuff
base.Render(writer);
}
Here I am posting the ASPX markup of the GridView also The ASPX
<asp:GridView ID="gvwProducts" runat="server"
AutoGenerateColumns="False" 
DataKeyNames="ProductID"
DataSourceID="sdsProducts"
OnRowDataBound="gvwProducts_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Contact Name">
<ItemTemplate>
<asp:Label ID="lblProductName" runat="server"
Text='<%#Eval("ProductName") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Stock">
<ItemTemplate>
<asp:Label ID="lblunitsInStock" runat="server"
Text='<%#Eval("UnitsInStock") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>

</Columns>
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
</asp:GridView>
<asp:SqlDataSource ID="sdsProducts" runat="server" 
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT ProductID, ProductName, UnitsInStock FROM Products"
SelectCommandType="Text">
</asp:SqlDataSource>
Just paste the last xml snippet on ASPX and first two code snippets on cs page. Change the connectionstring to the one you have and run the code to see the result. We are not finished yet From time to time, some developers will experience the "__doPostBack object expected" error in the page Postback. This occurs at the second time we try to fire the row click event The Reason
We add onclick feature for GridView in the RowDataBound event using ClientScript.GetPostBackClientHyperlink(...) But RowDataBound event gets fired only the first time(at !IsPostBack). This creates the __doPostBack() function when the page is first time loaded. Now from the second time onwards(at IsPostBack) RowDataBound doesn't get fired. So no ClientScript.GetPostBackClientHyperlink(...) is called and no __doPostBack() function is created
The solution. Just place this line under Page_Load event
protected void Page_Load(object sender, EventArgs e)
{
ClientScript.GetPostBackClientHyperlink(this, "");
}

Happy Coding! For Better understanding please read Selectable GridViewRow using JavaScript Points to Note: 1. I have given a SelectedRowStyle to show that the row is actually selected by giving it a different color. 2. The table used is Products from Microsoft's Sample DataBase Northwind
Read more...

Thursday, August 27, 2009

Sorting and Paging a GridView

2 comments
Sorting can be tricky. But maintaining the sort order on paging is trickier
Here is a sample code for that

DataBase used is Northwind.
Table used is Products.

The ASPX



<asp:GridView ID="GridView1" runat="server"
AllowPaging="true"
AllowSorting="true"
AutoGenerateColumns="false"
DataKeyNames="ProductID"
PageSize="10"
OnPageIndexChanging="GridView1_PageIndexChanging"
OnSorting="GridView1_Sorting">
<Columns>
<asp:TemplateField HeaderText="ID" SortExpression="ProductID">
<ItemTemplate>
<asp:Label ID="lblProductID" runat="server"
Text='<%#Eval("ProductID") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name" SortExpression="ProductName">
<ItemTemplate>
<asp:Label ID="lblProductName" runat="server"
Text='<%#Eval("ProductName") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Stock" SortExpression="UnitsInStock">
<ItemTemplate>
<asp:Label ID="lblUnitsInStock" runat="server"
Text='<%#Eval("UnitsInStock") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>



The ASPX.CS



private const string ASCENDING = " ASC";
private const string DESCENDING = " DESC";
static private DataView dvProducts;

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
dvProducts = new DataView(GetProductsFromDataTable());
BindGridView();
}
}

protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
string sortExpression = e.SortExpression;

if (GridViewSortDirection == SortDirection.Ascending)
{
GridViewSortDirection = SortDirection.Descending;
dvProducts.Sort = sortExpression + DESCENDING;
BindGridView();
}
else
{
GridViewSortDirection = SortDirection.Ascending;
dvProducts.Sort = sortExpression + ASCENDING;
BindGridView();
}
}

protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
BindGridView();
}

private void BindGridView()
{
GridView1.DataSource = dvProducts;
GridView1.DataBind();
}

public SortDirection GridViewSortDirection
{
get
{
if (ViewState["sortDirection"] == null)
ViewState["sortDirection"] = SortDirection.Ascending;

return (SortDirection)ViewState["sortDirection"];
}
set { ViewState["sortDirection"] = value; }
}

private DataTable GetProductsFromDataTable()
{
DataTable dtProductsTemp = new DataTable();
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString))
{
using (SqlDataAdapter adapProducts = new SqlDataAdapter("Select * from Products", conn))
{
adapProducts.Fill(dtProductsTemp);
}
}
return dtProductsTemp;
}



Extra namespace used



using System.Data.SqlClient;


Read more...

Saturday, July 18, 2009

Paging in Repeater

0 comments
Heres a sample on how to implement Paging on a Repeater.

The Output



The ASPX

<asp:Repeater ID="rptrProducts" runat="server">
<HeaderTemplate>
<table border="1">
<tr style="background-color:Gray;">
<td>
Product Name
</td>
<td>
Quantity Per Unit
</td>
<td>
Units On Order
</td>
<td>
Discontinued
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="lblProductName" runat="server" Text='<%#Eval("ProductName") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblQuantityPerUnit" runat="server" Text='<%#Eval("QuantityPerUnit") %>'></asp:Label>
</td>
<td>
<asp:Label ID="lblUnitsOnOrder" runat="server" Text='<%#Eval("UnitsOnOrder") %>'></asp:Label>
</td>
<td>
<asp:CheckBox ID="chkDiscontinued" runat="server" Checked='<%#Eval("Discontinued") %>'
Enabled="false" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
<tr align="right" style="background-color:Gray;">
<td colspan="4">
<asp:LinkButton ID="lnkFirst" runat="server"
ForeColor="Black"
Text="First" onclick="lnkFirst_Click">
</asp:LinkButton>&nbsp;
<asp:LinkButton ID="lnkPrevious" runat="server"
ForeColor="Black"
Text="Previous"
OnClick="lnkPrevious_Click">
</asp:LinkButton>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Now Showing Page&nbsp;
<asp:DropDownList ID="ddlpageNumbers" runat="server"
AutoPostBack="true"
OnSelectedIndexChanged="ddlpageNumbers_SelectedIndexChanged">
</asp:DropDownList>&nbsp;of&nbsp;
<asp:Label ID="lblTotalPages" runat="server">
</asp:Label>&nbsp;Pages.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<asp:LinkButton ID="lnkNext" runat="server"
ForeColor="Black"
Text="Next" onclick="lnkNext_Click">
</asp:LinkButton>&nbsp;
<asp:LinkButton ID="lnkLast" runat="server"
ForeColor="Black"
Text="Last" onclick="lnkLast_Click">
</asp:LinkButton>
</td>
</tr>
</table>


The ASPX.CS

public partial class Repeaters_Paging : System.Web.UI.Page
{
#region "Local Variables and Declarations"

private const bool blnAllowPaging = true;
private const int iPageSize = 10;

private static PagedDataSource pgdProducts = new PagedDataSource();

#endregion

#region "Page Load Event"

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindRepeater();
}
}

#endregion

#region "Footer LinkButtons"

protected void lnkFirst_Click(object sender, EventArgs e)
{
ThisPageNumber = 0;
BindRepeater();
}

protected void lnkPrevious_Click(object sender, EventArgs e)
{
--ThisPageNumber;
BindRepeater();
}

protected void lnkNext_Click(object sender, EventArgs e)
{

++ThisPageNumber;
BindRepeater();
}

protected void lnkLast_Click(object sender, EventArgs e)
{
ThisPageNumber = pgdProducts.PageCount - 1;
BindRepeater();
}

#endregion

#region "Footer DropDownList"

protected void ddlpageNumbers_SelectedIndexChanged(object sender, EventArgs e)
{
ThisPageNumber = ddlpageNumbers.SelectedIndex;
BindRepeater();
}

#endregion

#region "Custom Functions"

private void BindRepeater()
{
pgdProducts.AllowPaging = blnAllowPaging;
pgdProducts.PageSize = iPageSize;
pgdProducts.DataSource = GetProductsDataView();

pgdProducts.CurrentPageIndex = ThisPageNumber;
lblTotalPages.Text = pgdProducts.PageCount.ToString();
FillPagesDropDownList(pgdProducts.PageCount);

lnkFirst.Enabled = !pgdProducts.IsFirstPage;
lnkPrevious.Enabled = !pgdProducts.IsFirstPage;
lnkNext.Enabled = !pgdProducts.IsLastPage;
lnkLast.Enabled = !pgdProducts.IsLastPage;
ddlpageNumbers.SelectedIndex = pgdProducts.CurrentPageIndex;

rptrProducts.DataSource = pgdProducts;
rptrProducts.DataBind();
}

private DataView GetProductsDataView()
{
DataTable dtProductsTemp = new DataTable();
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString))
{
using (SqlDataAdapter adapProducts = new SqlDataAdapter("Select * from Products", conn))
{
adapProducts.Fill(dtProductsTemp);
}
}
return dtProductsTemp.DefaultView;

}

private void FillPagesDropDownList(int iTotalPages)
{
ddlpageNumbers.Items.Clear();
for (int i = 1; i <= iTotalPages; i++)
{
ddlpageNumbers.Items.Add(new ListItem(i.ToString(), i.ToString()));
}
}

#endregion

#region "Properties"

private int ThisPageNumber
{
get
{
object obj = ViewState["ThisPageNumber"];
return (obj == null) ? 0 : (int)obj;
}
set
{
this.ViewState["ThisPageNumber"] = value;
}
}

#endregion

}

Extra Namespace used

using System.Data.SqlClient;

P.S: DataBase used is Northwind
Read more...