Wednesday, March 25, 2009

Paging a Filtered GridView

0 comments
In many forums there are people struggling with filtering and paging in gridview.
When separated, both filtering and paging works smoothly.
But when trying to change the page index of a filtered result set, all hell will break loose.
Mostly a new page with the unfiltered result set comes into play.


Here's a sample on how to do it.


The ASPX



<table>
<tr>
<td>
Search By Product Name:
</td>
<td>
<asp:TextBox ID="txtProductName" runat="server"></asp:TextBox>
</td>
<td>
<asp:Button ID="btnBindGridView" runat="server"
Text="Populate Grid" onclick="btnBindGridView_Click" />
</td>
</tr>
<tr>
<td colspan="3">
<asp:GridView ID="gvwProducts" runat="server"
AllowPaging="true"
AutoGenerateColumns="false"
PageSize="3"
OnPageIndexChanging="gvwProducts_PageIndexChanging">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product Name"/>
<asp:BoundField DataField="QuantityPerUnit" HeaderText="Quantity"/>
<asp:BoundField DataField="UnitPrice" HeaderText="Price"/>
</Columns>
</asp:GridView>
</td>
</tr>
</table>



The ASPX.CS



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

protected void btnBindGridView_Click(object sender, EventArgs e)
{
BindGridView();
}

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

private void BindGridView()
{
DataTable dtProducts = new DataTable();
string strSelectCommand = "SELECT * FROM Products"
+ ((txtProductName.Text.Trim() == "") ? "" : (" WHERE ProductName LIKE '" + txtProductName.Text.Trim() + "%'"));
using (SqlConnection sqlConn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString))
{
using (SqlDataAdapter adapProducts = new SqlDataAdapter(strSelectCommand, sqlConn))
{
adapProducts.Fill(dtProducts);
}
}
gvwProducts.DataSource = dtProducts;
gvwProducts.DataBind();
}



DataBase used --> Northwind
Extra Namespace used -->System.Data.SqlClient;

Hope this helps!
Read more...

Monday, March 16, 2009

Filtered GridView using DataList

1 comments
Many times the requirement comes like this.

need to show the first letter of products as a link outside grid and when the user clicks on it the grid will be showing the result with that particular product only.


Can be easily done using GridView and DataList.
Database used is Northwind.

The ASPX



<asp:DataList ID="dlstProducts" runat="server"
RepeatDirection="Horizontal">
<ItemTemplate>
<asp:LinkButton ID="lnkFirstLetters" runat="server"
Text='<%# Bind("ProductNameFirstLetter") %>'
onclick="lnkFirstLetters_Click">
</asp:LinkButton>
</ItemTemplate>
</asp:DataList>

<asp:GridView ID="gvwProducts" runat="server"
AutoGenerateColumns="false"
DataKeyNames="ProductID">
<Columns>
<asp:TemplateField HeaderText="Product Name">
<ItemTemplate>
<asp:Label ID="lblProductName" runat="server" Text='<%# Bind("ProductName") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Quantity Per Unit">
<ItemTemplate>
<asp:Label ID="lblQuantityPerUnit" runat="server" Text='<%# Bind("QuantityPerUnit") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>



The ASPX.CS



public partial class GridView_GridViewDataListFirstAlphabet : System.Web.UI.Page
{
DataTable dtProducts = new DataTable();

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

protected void lnkFirstLetters_Click(object sender, EventArgs e)
{
BindGridView(((LinkButton)sender).Text.Trim());
}

private void InitialBindOfControls()
{
BindGridView("Initial");
BindDataList();
}

private void BindGridView(string strChar)
{
string strQuery = "SELECT ProductID, ProductName, QuantityPerUnit FROM Products "
+ ((strChar == "Initial") ? "" : "WHERE ProductName LIKE'" + strChar + "%'")
+ "ORDER BY ProductName";
using (SqlConnection sqlConn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ToString()))
{
using (SqlDataAdapter adapProducts = new SqlDataAdapter(strQuery, sqlConn))
{
adapProducts.Fill(dtProducts);
gvwProducts.DataSource = dtProducts;
gvwProducts.DataBind();
}
}
}

private void BindDataList()
{
if (gvwProducts.Rows.Count != 0)
{
DataTable dtTemp = new DataTable();
dtTemp.Columns.Add("ProductNameFirstLetter");
dtTemp.Rows.Add(((Label)gvwProducts.Rows[0].FindControl("lblProductName")).Text.Substring(0, 1));
foreach (GridViewRow gvrProducts in gvwProducts.Rows)
{
if (dtTemp.Rows[dtTemp.Rows.Count - 1][0].ToString() != ((Label)gvrProducts.FindControl("lblProductName")).Text.Substring(0, 1))
{
dtTemp.Rows.Add(((Label)gvrProducts.FindControl("lblProductName")).Text.Substring(0, 1));
}
}
dlstProducts.DataSource = dtTemp;
dlstProducts.DataBind();
}
}
}



Extra Namespace used


using System.Data.SqlClient;

Read more...

Monday, February 2, 2009

Maintaining State of CheckBox while Paging in GridView

0 comments
The Logic
We are storing the primary keys of the checkboxes that are checked into a List where T = data type of the primary key. This is done at PageIndexChanging before we change the page index and re-bind the GridView. And at RowDataBound we are checking whether the DataKeyName(primary key) of each row is in the List. If present , we mark the CheckBox as checked.
Heres the sample code.

The ASPX

<asp:LinkButton ID="btnSelectAllPage" runat="server" 
            CommandName="SelectAllPage" 
            Text="Select All Pages"
            OnCommand="SelectDeselectAllPages" />|
<asp:LinkButton ID="btnDeselectAllPage" runat="server" 
            CommandName="DeselectAllPage" 
            Text="Deselect All Pages"
            OnCommand="SelectDeselectAllPages" />|
<asp:LinkButton ID="btnSelectAll" runat="server" 
            CommandName="SelectAll" 
            Text="Select Page"
            OnCommand="SelectDeselect" />|
<asp:LinkButton ID="btnDeselectAll" runat="server" 
            CommandName="DeselectAll" 
            Text="Deselect Page"
            OnCommand="SelectDeselect" />

<asp:GridView ID="gvProducts" runat="server" 
            AllowPaging="True" 
            AutoGenerateColumns="False"
            DataKeyNames="ProductID"
            OnPageIndexChanging="gvProducts_PageIndexChanging" 
            OnRowDataBound="gvProducts_RowDataBound">
    <Columns>
        <asp:TemplateField HeaderText="Select">
            <ItemTemplate>
                <asp:CheckBox ID="chkSelect" runat="server" />
            </ItemTemplate>
        </asp:TemplateField>
    <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False"
    ReadOnly="True" SortExpression="ProductID" />
    <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
    </Columns>
</asp:GridView>
<asp:SqlDataSource ID="sdsProducts" runat="server"
                ConnectionString='<%$ ConnectionStrings:NorthwindConnectionString %>'
                SelectCommand="SELECT * FROM Products">
</asp:SqlDataSource>



The ASPX.CS

private List<int> ProductIDs
{
    get
    {
        if (this.ViewState["ProductIDs"] == null)
        {
            this.ViewState["ProductIDs"] = new List<int>();
        }
        return this.ViewState["ProductIDs"] as List<int>;
    }
}

protected void SelectDeselect(object sender, CommandEventArgs e)
{
    foreach (GridViewRow gvr in gvProducts.Rows)
    {
        CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;
        if (chkSelect != null)
        {
            chkSelect.Checked = e.CommandName.Equals("SelectAll");
        }
    }
}

protected void SelectDeselectAllPages(object sender, CommandEventArgs e)
{
    DataSourceSelectArguments dssa = new DataSourceSelectArguments();
    dssa.AddSupportedCapabilities(DataSourceCapabilities.RetrieveTotalRowCount);
    dssa.RetrieveTotalRowCount = true;
    DataView dv = (DataView)sdsProducts.Select(dssa);
    foreach (DataRow dr in dv.Table.Rows)
    {

        int productID = Convert.ToInt32(dr.ItemArray[0]);//ItemArray[0] cos ProductID is in the first column
        if (e.CommandName.Equals("SelectAllPage") && !this.ProductIDs.Contains(productID))
        {
            this.ProductIDs.Add(productID);
        }
        if (e.CommandName.Equals("DeselectAllPage") && this.ProductIDs.Contains(productID))
        {
            this.ProductIDs.Remove(productID);
        }
    }
    foreach (GridViewRow gvr in gvProducts.Rows)
    {
        CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;
        if (chkSelect != null)
        {
            chkSelect.Checked = e.CommandName.Equals("SelectAllPage");
        }
    }
}

protected void gvProducts_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    foreach (GridViewRow gvr in gvProducts.Rows)
    {
        CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;
        if (chkSelect != null)
        {
            int productID = Convert.ToInt32(gvProducts.DataKeys[gvr.RowIndex]["ProductID"]);
            if (chkSelect.Checked && !this.ProductIDs.Contains(productID))
            {
                this.ProductIDs.Add(productID);
            }
            else if (!chkSelect.Checked && this.ProductIDs.Contains(productID))
            {
                this.ProductIDs.Remove(productID);
            }
        }
    }
}

protected void gvProducts_RowDataBound(object sender, GridViewRowEventArgs e)
{
    GridViewRow gvr = e.Row;
    if (gvr.RowType == DataControlRowType.DataRow)
    {
        CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;
        if (chkSelect != null)
        {
            int productID = Convert.ToInt32(gvProducts.DataKeys[gvr.RowIndex]["ProductID"]);
            chkSelect.Checked = this.ProductIDs.Contains(productID);
        }
    }
}

As an extra enhancement, we are also giving provision for selecting, deselecting both page and the whole rows in every page also here.

P.S: We are using Northwind Sample DataBase by Microsoft, so if you dont have it download it.

Courtesy: A wonderful post by Ed Bruck at forums.asp.net
Read more...