Library tutorials & articles
Selecting, Confirming & Deleting Multiple Checkbox Items In A DataGrid/GridView - Part 2: Maintaining CheckBox State Acr
- Introduction
- Our Main Page
- Storing and Maintaining DataGrid CheckBox Values
- Repopulate our DataGrid
- ASP.NET 2.0 GridView Version
- Conclusion
Storing and Maintaining DataGrid CheckBox Values
Now, the logic behind maintaining current pages values and recalling them in the current page all takes place for the most part in the DataGrid Paging function, where in between paging and databinding two things occur. One, is to find out which checkboxes were selected prior the DataGrid being paged - this being done by the GetCheckBoxValues() method listed below. And the other, is to store them by means of Session State.
The code presented below is what parses the DataGrid's checkboxes and determines which ones are selected, if any, using the FindControl method. It then holds the selected values via the DataGrid's DataKeyField property for each checkbox selected and adds them all into an ArrayList, which in turn is added to Session State.
Sub GetCheckBoxValues() 'As paging occurs store checkbox values
CheckedItems = New ArrayList
'Loop through DataGrid Items
For Each dgItem In MyDataGrid.Items
'Retrieve key value of each record based on DataGrids
' DataKeyField property
ChkBxIndex = MyDataGrid.DataKeys(dgItem.ItemIndex)
CheckBox = dgItem.FindControl("DeleteThis")
'Add ArrayList to Session if it doesnt exist
If Not IsNothing(Session ("CheckedItems")) Then
CheckedItems = Session ("CheckedItems")
End If
If CheckBox.Checked Then
BxChkd = True
'Add to Session if it doesnt already exist
If Not CheckedItems.Contains(ChkBxIndex) Then
CheckedItems.Add(ChkBxIndex.ToString())
End If
Else
'Remove value from Session when unchecked
CheckedItems.Remove(ChkBxIndex.ToString())
End If
Next
'Update Session with the list of checked items
Session ("CheckedItems") = CheckedItems
End Sub
Now that we've discussed the methodology for storing the selected boxes. What about paging back and forth and checking boxes arbitrarily and sorting, won't this whack the order and such out of place? Nope. For instance, if you select any two checkboxes on the first page, then page to the next, the second you page back your page is repopulated with your previously selected values. So if you remove them all, then page again, the aforementioned method deletes the values in the Session State, so when you page back, they're gone.
But say you didn't uncheck any, but rather checked off a couple more, then paged again. Well, same the logic applies here as well, we easily determine upon paging, one, that you already have existing values in Session State for the given page, which in truth is the ID field and not necessarily the page itself. And two, all that is now left to do is update Session State with the new ID values.
The function responsible for delegating the actions at the appropriate time resides in the DataGrid paging event handler method. Here it where it determines which checkboxes were selected, then it does it thing. After Databind has occurred we call the RePopulateCheckBoxes() method to tell us if the given page we've paged to has checkboxes it needs to repopulate.
Sub MyDataGrid_Page (sender As Object, e As DataGridPageChangedEventArgs)
'Get CheckBoxValues before paging occurs
GetCheckBoxValues()
MyDataGrid.CurrentPageIndex = e.NewPageIndex
BindData(Session ("SortOrder"))
'Populate current DataGrid page with the current page items from Session after databind
RePopulateCheckBoxes ()
End Sub
Once all this happens you have each DataGrid page filled with the correct boxes checked or empty. Pretty cool! Now, how does one repopulate the checkboxes on any page?
Related articles
Related discussion
-
hey developers out there
by pitsophera (0 replies)
-
Using ADO.NET with SQL Server
by Manjot Bawa (23 replies)
-
High-Performance .NET Application Development & Architecture
by Manjot Bawa (0 replies)
-
An Introduction to VB.NET and Database Programming
by carlosmen (14 replies)
-
OLEDB Connection running like a dog.
by kruelintent (3 replies)
Related podcasts
-
ADO.NET Data Services in .NET 3.5 Service Pack 1 Beta1 with ASP.NET AJAX
Wally walks through using ASP.NET Podcast Show #114 - ADO.NET Data Services in .NET 3.5 Service Pack 1 Beta1 with ASP.NET AJAX.
Events coming up
-
Nov
18
15 Minutes of Fame
Dresher, United States
This is a yearly tradition. We select 10 of the favorite speakers from monthly meetings, code camps, and hands on labs. Each one does a 15 minute talk on their favorite .NET technology. This is our 10th anniversary so we plan a gala event with special prizes and refreshments.
hi all,
i faced the same problem, but i have paging in the grid view, so my problem is
when user checks one record in a page and goes to the next page and selects some records there, when he returns to the previous page we need to keep the checked state of whatever records he had checked earlier. When he is finished checking through the pages, he needs a list of records he has checked to delete them form database
iam a new in this forum, i need any one help me as i searched alot and i didn't find any solution
thanks
Hi Dimitrios,
Thanks for such a great tutorial. It works for me. Keep it up.
Oleg
my code under delete button_click event is this
foreach(GridViewRow row in Exp_SummaryGrid.Rows)
{
string cname = row.cells[0].text;
string del = "delete from exp_summary where company=" + cname;
CheckBox cb = (CheckBox)row.Cells[4].Controls[1];
if (cb.Checked==true)
{
SqlCommand delsql = new SqlCommand();
delsql.Connection = conn;
delsql.CommandText = del;
delsql.CommandType = CommandType.Text;
SqlDataAdapter da = new SqlDataAdapter(del, conn);
da.DeleteCommand = delsql;
DataSet ds2 = new DataSet();
da.Update(ds2, "exp_summary");
}
}
Hey Thanks! Good suggestions. Now the question remains in getting to those :-) As for .NET 2.0, this article has it already included.
Thanks again!
Having tried your solution I was impressed by the ease with which it worked and it started me thinking of extensions to the principle.
Can I request that you extend the sample code with some additional features?
Firstly add an option to take all the selected records and then insert them into another file. One possible use of this would be to create a shopping 'wish list'.
Secondly to add an update feature. One use of this would be to amend prices of a products in price list, and produce a listing/report before committing the amendments.
Thirdly, add a count of records selected (displayed in the footer?).
And to be really cheeky, can you do it in ASP.NET 2.0 (in case you finish your version before I finish mine) ;-)
Got if figured out. Seems that I inadvertantly had two select_deselectAll routines so it didn't know which to use. Even though in visual studeo it indicates that you cant, via a squiggle under the onclick, have an OnClick event for the asp:Checkbox, you can point it to a javascript routine since that runs only on the client. Also I removed the OnCheckChanged. - john
In net 1.1 how do you get the CheckAll to work? First, I cant use the OnClick since it is not available. Second, if I try to use the OnCheckChanged event I cant point it to the javascript selectdeselectAll routine because it is not a member of 'ASP.mDatagridaspx'. How do you apply events to a datagrid checkbox? Other things are working fine but sure frustrating to not figure this out. - john
Yevgeniy,
No, not at all. No big deal really. We all hope to learn, as I from you as well.:D
Thanks, and equal respect to you.:)
-Jimmy
Well Dimitrios... must admit when you provided those links on StringBuilder vs static concatenation, I just quickly looked through them and was sure that was just another article advocating for static concatenations when the number of strings is known. Now I read it carefully and was surprised and ashamed... It seems like it's me who would be "seeding bad practices" in such a case... Sorry and my respect to you...
No, I appreciate the point you're trying to get across Yevgeniy. At any rate, as I indicated earlier, I agree with you when the concatenation is for minimal strings, but when you are concatenating numerous strings or functions the overhead in instantiation is overall justified I feel, and better practice.
But either way, you're not really going to notice much truly in the way of performance, especially when you apply other performance enhancing techniques, ie, disabling debugging and tracing, closing connections, or even better bind a Datagrid from a Datareader instead of a DataSet for even greater advantages in speed, etc. In .NET, it's the collective means, rather than one tweak, that'll determine a scalable and efficient application.
This applies to looping page size, that in my experience simply displaying a few hundred per page is still ill-advised, and with anything one does in greater magnitude, comes with it degrading performance regardless of much code manipulation.
I meant that instead of
stringBuilder.Append(str1);
stringBuilder.Append(str2);
stringBuilder.Append(str3);
you'd better use
str1 + str2 + str3
That's definitelly gonna be better.
As for looping through form elements, I agree, it raises an issue only on a large amount of form elements. But who knows how large is going to be a particular page in question your readers will be working on.
Yevgeniy,
Thanks for your input, but I would have to disagree on looping through all the elements on the given page being a performance issue, when it's looping through 10 checkboxes per page, not a million. Additionally, utilizing state management via session or viewstate further enhances performance and scalability. So there's no such thing as suboptimal when you perform the task at hand in the manner best suited.
Now regarding your bias using the Stringbuilder class, again I would disagree. First of all, it's good practice in using Stringbuilder as there is performance advantages over static string concatenation - How StringBuilder string concatenation affects performance , string builder vs string concatenation "+" and Use StringBuilder to Build Strings Efficiently. So in my example it’s fine and justified.
I will however give you this though, that I definitely agree with you on not using StringBuilder for 5 lines of code. Incidentally, in Part 1 of my article I did in fact use string concatenation if that makes a difference for you.
But all in all Yevgeniy, I wouldn't just go out and post comments on articles unless you truly have facts to support your claims, which is why the statements you’ve made can "seed a bad practice, especially among newbies."
while thank you very much for this article and other I was lucky to read before, I must admit there are times when you suggest a way to solve a problem in a quite suboptimal way.
It's rarely good to loop through all form elements to find checkboxes appropriate. Well must admit under normal circumstances it can hardly pose a performance hit, but still when number of records is high or the html file is large (which is not good, I know, but I saw times when there seemed to be no other way), it takes a certain amount of time to iterate through all elements. I think it's better to have a client-side array of ids of all checkboxes in question. And on the server side you just emit client side code for each checkbox to register itself with that array. In this case anytime you need to loop through all checkboxes you simply loop through array elements which is much better from performanse standpoint.
Then, I saw how you suggested to create client-side code via a long series of StringBuilder's Append method while it could have been done through static string concatenation. You can seed a bad practice, especially among newbies
No time to write more, gotta be going
Thank you for your articles. Usually, I like them
Yevgeniy
Since I have had this article published here, I have now also been able to implement a way to highlight the selected row or entire set of rows and maintain this state across pages just as in my article, with of course the added benefit of showing users which row(s) they've checked, even when they happen to page back.
To get this going, follow these four steps.
First, add the style properties to the DataGrid:
<SelectedItemStyle BackColor="#F5EDED" ForeColor="Black">
</SelectedItemStyle>
<ItemStyle BackColor="White" ForeColor="Black">
</ItemStyle>
Second, add the highlightChkBxRow(this); JavaScript function call to both checkbox onClick events, so it now becomes:
OnClick="javascript: highlightChkBxRow(this); return select_deselectAll (this.checked, this.id);"
Third, in the code behind - add the following JS function within the Registered Script Block section to handle the client side checkboxes:
.Append ("function highlightChkBxRow(chkbx) {" & nl & nl)
.Append (" if (chkbx.id.indexOf ('DeleteThis') != -1) {" & nl & nl)
.Append (" if (chkbx.checked) {" & nl & nl)
.Append (" chkbx.parentElement.parentElement.style.backgroundColor='#F5EDED';" & nl)
.Append (" chkbx.parentElement.parentElement.style.color='#000000';" & nl)
.Append (" } else {" & nl & nl)
.Append (" chkbx.parentElement.parentElement.style.backgroundColor='#FFFFFF';" & nl)
.Append (" chkbx.parentElement.parentElement.style.color='#000000';" & nl & nl)
.Append (" }" & nl & nl)
.Append (" } else {" & nl & nl)
.Append (" var frm = document.forms[0];" & nl & nl)
.Append (" for (h = 0; h < frm.length; h++) {" & nl & nl)
.Append (" if (frm.elements[h].id.indexOf ('DeleteThis') != -1) {" & nl & nl)
.Append (" if (chkbx.id.indexOf ('CheckAll') != -1 && chkbx.checked) {" & nl & nl)
.Append (" frm.elements[h].parentElement.parentElement.style.backgroundColor='#F5EDED';" & nl)
.Append (" frm.elements[h].parentElement.parentElement.style.color='#000000';" & nl & nl)
.Append (" } else {" & nl & nl)
.Append (" frm.elements[h].parentElement.parentElement.style.backgroundColor='#FFFFFF';" & nl)
.Append (" frm.elements[h].parentElement.parentElement.style.color='#000000';" & nl & nl)
.Append (" }" & nl)
.Append (" }" & nl)
.Append (" } //loop" & nl)
.Append (" }" & nl)
.Append ("}" & nl)
And, finally to maintain our selected rows across pages, replace the RePopulateCheckBoxes () method with the one listed below:
Sub RePopulateCheckBoxes ()
CheckedItems = New ArrayList
CheckedItems = Session ("CheckedItems")
If Not IsNothing(CheckedItems) Then
'Loop through DataGrid Items
For Each dgItem in MyDataGrid.Items
ChkBxIndex = MyDataGrid.DataKeys(dgItem.ItemIndex)
'Repopulate DataGrid with items found in Session
If CheckedItems.Contains(ChkBxIndex) Then
CheckBox = CType(dgItem.FindControl("DeleteThis"), CheckBox)
CheckBox.Checked = True
dgItem.ForeColor = MyDataGrid.SelectedItemStyle.ForeColor
dgItem.BackColor = MyDataGrid.SelectedItemStyle.BackColor
Else
dgItem.ForeColor = MyDataGrid.ItemStyle.ForeColor
dgItem.BackColor = MyDataGrid.ItemStyle.BackColor
End If
Next
End If
'Copy ArrayList to a new array
Results = CheckedItems.ToArray(GetType(String))
'Concatenate ArrayList with comma to properly send for deletion
deletedIds = String.Join(",", Results)
End Sub
And that's it. You're now able to offer the user the added functionality of highlighting the row they've checked or all the rows and persist their selections across pages!
-Jimmy Markatos
This thread is for discussions of Selecting, Confirming & Deleting Multiple Checkbox Items In A DataGrid/GridView - Part 2: Maintaining CheckBox State Acr.