groovbox303
asked on
Mantaining checkboxes State with Gridview Paging
Hi Experts,
I need some help with a problem, I have a template checkbox column in m gridview. I have a custom sorting and paging procedure. The checkboxes do no persist their state going through different pages in the Gridview, I have found many incomplete solutions to this online. can someone help me out with providing a complete way (in VB.NET) to achieve this functionality. I am working with VB.NET and ASP.NET 2.0. I have my Gridview's viewstate enabled true, and have tried the following links but they did not work. Also there is a select all unselect All checkbox header checkbox, I could not get the javascript examples to work so ended up using a serverside solution for it, the header checkbox loses its state as well going between the gridview pages.
http://aspalliance.com/774
* This solution only works if the number of results is less then the page size, I cannot use this since some of my gridviews have 30, 40+ pages.
http://www.dotnetjunkies.com/HowTo/9D01155A-A413-454A-98DE-977D540CF35D.dcik
*Applicable to .NET 1.1, I am using 2.0
Thanks in advance, I have seen a lot of other people come across the same problem online, hopefully someone here can provide a solution to this
I need some help with a problem, I have a template checkbox column in m gridview. I have a custom sorting and paging procedure. The checkboxes do no persist their state going through different pages in the Gridview, I have found many incomplete solutions to this online. can someone help me out with providing a complete way (in VB.NET) to achieve this functionality. I am working with VB.NET and ASP.NET 2.0. I have my Gridview's viewstate enabled true, and have tried the following links but they did not work. Also there is a select all unselect All checkbox header checkbox, I could not get the javascript examples to work so ended up using a serverside solution for it, the header checkbox loses its state as well going between the gridview pages.
http://aspalliance.com/774
* This solution only works if the number of results is less then the page size, I cannot use this since some of my gridviews have 30, 40+ pages.
http://www.dotnetjunkies.com/HowTo/9D01155A-A413-454A-98DE-977D540CF35D.dcik
*Applicable to .NET 1.1, I am using 2.0
Thanks in advance, I have seen a lot of other people come across the same problem online, hopefully someone here can provide a solution to this
ASKER
Hi Ramuncikas,
ok I have implemented something similar to what you are mentioning and it is working to some extent but definately in not all cases. I will post an example here in the code. Its just an array of country names I bind to the grid. I use an arraylist and store it in session and retrieve it in another function the only way I could see the user selected options was to put these functions in the Databinding event. Here is the kicker, since I am using custom paging and sorting, I cannot just bind the grid once. I have to bind it if first the user wants to see it by clicking on the checkbox and then on every page. This is the only way I have seen custom paging work with examples online. Please check out my functions for remembering the checked boxes and redoing them after binding the gridview. If you test this example you will see it works if you make a few choices on one page and few on another. but where this does not work is when a user can go back and unselect all their options on a page. Also their is a hidden html input called hdoption, if the user selects the select all option the value for this is changed to all and all checkboxes are selected for pages. But I cant seem to mantain the state of the html header checkbox and work out the logic for storing different combinations for all scenarios. If you can provide a working example of this scenario Id really appreciate it. Here is the code. thanks for your help again.
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="HtmlControlTestVb._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<script type="text/javascript">
function executeCheck(elem){
if(elem.checked) SetAllCheckBoxes("form1","myBox",true);
else SetAllCheckBoxes("gridview1",false);
}
function SetAllCheckBoxes(gridview, CheckValue){
var objCheckBoxes = document.getElementById(gridview).getElementsByTagName("input");
var option = document.getElementById("hdoption");
var cb = document.getElementById("Headercb");
if(cb.checked)
{
option.value = "All";
}
else
{
option.value = "None";
}
if(!objCheckBoxes)
return;
var countCheckBoxes = objCheckBoxes.length;
if(!countCheckBoxes)
objCheckBoxes.checked = CheckValue;
else
// set the check value for all check boxes
for(var i = 0; i < countCheckBoxes; i++)
objCheckBoxes[i].checked = CheckValue;
}
</script>
</head>
<body>
<form id="form1" runat="server" >
<div>
<span>This checkbox at the top is optional only if this is selected is the gridview loaded</span>
<asp:CheckBox ID="chkview" runat="server" Text="Select if you want to choose countries" AutoPostBack="True" />
<br />
<br />
<table style="FONT-SIZE: 10pt; WIDTH: 872px; FONT-FAMILY: arial" >
<tr id="rowGrid" runat="server" style="">
<td>
<input type="checkbox" onclick="executeCheck(this)" id="headercb"/>Select/UnSelect All
<asp:GridView CssClass='Gridview' ID="gridview1" runat="server" AutoGenerateColumns="False" CellPadding="4" GridLines="Vertical" AllowPaging="True" AllowSorting="True" PageSize="5" BackColor="White" BorderColor="#DEDFDE" BorderStyle="None" BorderWidth="1px" ForeColor="Black">
<Columns>
<asp:BoundField DataField="Country" HeaderText="Country" />
<asp:TemplateField>
<ItemTemplate>
<input type="checkbox" name="myBox" value="1" runat="server" id="mycheckBox" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle BackColor="#CCCC99" />
<RowStyle BackColor="#F7F7DE" />
<SelectedRowStyle BackColor="#CE5D5A" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#F7F7DE" ForeColor="Black" HorizontalAlign="Right" />
<HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
<input id="hdoption" type="hidden" runat="server" enableviewstate="true" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
CODE BEHIND:
Imports System.Data
Imports System.Text
Partial Public Class _Default
Inherits System.Web.UI.Page
Dim countries As String() = Regex.Split("Japan,America,England,USA,Nigeria,China,Pakistan,Brazil,Mexico,Canada,France,Spain,Argentina,Bahamas,Puerto Rico,Russia", ",")
Private cObjs As ArrayList
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Session.Add("ShowGrid", "None")
End If
'If (chkview.Checked) Then
' If Session.Item("ShowGrid") = "None" Then
' BindGrid()
' End If
'End If
BindGrid()
'If Page.IsPostBack Then
' RememberChecked()
'End If
End Sub
Protected Sub BindGrid()
Dim Row As DataRow
Dim table As New DataTable("Test")
table.Columns.Add("Country")
Dim i As Int32
Dim Count = countries.Length - 1
For i = 0 To Count
Row = table.NewRow
Row("Country") = countries(i)
table.Rows.Add(Row)
Next
Dim DS As New DataSet
DS.Tables.Add(table)
gridview1.DataSource = DS.Tables(0)
gridview1.DataBind()
End Sub
Protected Sub chkview_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkview.CheckedChanged
If chkview.Checked Then
rowGrid.Style("display") = "block"
Session.Item("ShowGrid") = "Block"
Else
rowGrid.Style("display") = "None"
Session.Item("ShowGrid") = "None"
End If
End Sub
Protected Sub gridview1_PageIndexChanging(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles gridview1.PageIndexChanging
gridview1.DataSource = SortDataTable(gridview1.DataSource, True)
gridview1.PageIndex = e.NewPageIndex
gridview1.DataBind()
RedoCheckBoxes()
End Sub
Protected Function SortDataTable(ByVal dataTable As DataTable, ByVal isPageIndexChanging As Boolean) As DataView
If Not dataTable Is Nothing Then
Dim dataView As New DataView(dataTable)
If GridViewSortExpression <> String.Empty Then
If isPageIndexChanging Then
dataView.Sort = String.Format("{0} {1}", GridViewSortExpression, GridViewSortDirection)
Else
dataView.Sort = String.Format("{0} {1}", GridViewSortExpression, GetSortDirection())
End If
End If
Return dataView
Else
Return New DataView()
End If
End Function
Private Property GridViewSortExpression() As String
Get
Return IIf(ViewState("SortExpression") = Nothing, String.Empty, ViewState("SortExpression"))
End Get
Set(ByVal value As String)
ViewState("SortExpression") = value
End Set
End Property
Private Function GetSortDirection() As String
Select Case GridViewSortDirection
Case "ASC"
GridViewSortDirection = "DESC"
Case "DESC"
GridViewSortDirection = "ASC"
End Select
Return GridViewSortDirection
End Function
Private Property GridViewSortDirection() As String
Get
Return IIf(ViewState("SortDirection") = Nothing, "ASC", ViewState("SortDirection"))
End Get
Set(ByVal value As String)
ViewState("SortDirection") = value
End Set
End Property
Protected Sub RememberChecked()
Dim CheckedItems As New ArrayList()
Dim PatID As String
For Each row As GridViewRow In gridview1.Rows
Dim cb As HtmlInputCheckBox = CType(row.FindControl("mycheckbox"), HtmlInputCheckBox)
PatID = row.Cells(0).Text
If Not IsNothing(Session("CheckedItems")) Then
CheckedItems = Session("CheckedItems")
End If
'If Checkbox is checked, Add to the arraylist otherwise if unchecked check to see if it is in arraylist,
'and if it is then remove it
If cb.Checked Then
If Not CheckedItems.Contains(PatID) Then
CheckedItems.Add(PatID)
End If
Else
If CheckedItems.Contains(PatID) Then
CheckedItems.Remove(PatID)
End If
End If
Next
'Update Session with the list of checked Items
Session("CheckedItems") = CheckedItems
End Sub
Protected Sub RedoCheckBoxes()
If hdoption.Value = "All" Then
For Each row As GridViewRow In gridview1.Rows
Dim cb As HtmlInputCheckBox = CType(row.FindControl("mycheckbox"), HtmlInputCheckBox)
cb.Checked = True
Next
Else
Dim CheckedItems As New ArrayList()
CheckedItems = Session("CheckedItems")
If Not IsNothing(CheckedItems) Then
'Loop through Gridview Items
Dim PatId As String
For Each row As GridViewRow In gridview1.Rows
Dim cb As HtmlInputCheckBox = CType(row.FindControl("mycheckbox"), HtmlInputCheckBox)
PatId = row.Cells(0).Text
If CheckedItems.Contains(PatId) Then
cb.Checked = True
End If
Next
End If
End If
End Sub
Protected Sub gridview1_Sorting(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles gridview1.Sorting
GridViewSortExpression = e.SortExpression
Dim pageIndex As Int16 = gridview1.PageIndex
gridview1.DataSource = SortDataTable(gridview1.DataSource, False)
gridview1.DataBind()
gridview1.PageIndex = pageIndex
End Sub
Protected Sub gridview1_DataBinding(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles gridview1.DataBinding
If Page.IsPostBack Then
CountMofos()
If IsNothing(Session("CheckedItems")) Then
RememberChecked()
ElseIf (gridview1.Rows.Count > 0) Then
If (Session.Item("Count") <> "0") Then
Dim CheckedItems As New ArrayList()
CheckedItems = Session("CheckedItems")
RememberChecked()
End If
End If
End If
End Sub
Protected Sub CountMofos()
If Not IsNothing(Session("CheckedItems")) Then
Dim Count As Int32 = 0
For Each row As GridViewRow In gridview1.Rows
Dim cb As HtmlInputCheckBox = CType(row.FindControl("mycheckbox"), HtmlInputCheckBox)
If cb.Checked Then
Count = Count + 1
End If
Next
Session.Add("Count", Count)
End If
End Sub
End Class
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
BTW, I did not implement sorting. This should be as simple as copy/paste from your code.
Hi,
Can the above solution be used when custom paging is done using ROW_NUMBER() ,that means getting only current page data from sql server
Can the above solution be used when custom paging is done using ROW_NUMBER() ,that means getting only current page data from sql server
Let me explain you the way gridview works.
Suppose you have a grid with page size set to 20 rows. You are pulling 600 records from database and binding them to grid. Grid takes only records needed and show them. The rest of records are only used to calculate the number of pages to show numbers in grid's pager. But these records are not persisted in viewstate.
When user changes page number (by clicking on "next" or "previous" arrows or by clicking page number) your page gets event notification that grid is changing page. What you do here is pull same 600 records from database and bind the to grid again. And again - grid takes only records to show and dumps the rest of them.
So even if you enable viewstate for your checkboxes grid is rebound on each page load and their state is lost.
What I would suggest is to track the state of your checkboxes manually. On the initial load of page, or to be more precise - on the initial load of data - you:
1. create a object of type Dictionary<string, bool>
2. cycle trough the rows of datatable and fill dictionary object with IDs and checkbox states of each row.
3. bind datatable to grid
4. store dictionary object to viewstate (for later use)
Next if user chooses to view another page of a grid you do the following:
1. get dictionary object from viewstate
2. cycle through the rows of a grid and save values of checkboxes to a dictionary object
3. fill datatable from database
4. bind datatable to grid
5. cycle through rows of grid and set values of checkboxes from a dictionary
This way dictionary object maintains the state of ALL chekboxes that your grid intends to show. What you do is only "manually mimic" the state of checkboxes.
I'd be hapy to show you some code for this, but unfortunatly I can do this in C# only.
Hope this helps
Feel free to ask further questions if any.
Ramuncikas