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
ASP.NET 2.0 GridView Version
With .NET 2.0 now being official it was only a given for me to convert the code for .NET 2.0's Gridview. Before I present the updated code, I'll now discuss the changes that have occurred in converting the code from a DataGrid to a GridView.
First off, the code-behind model has changed. In the @Page directive, accessing your code behind is accomplish via the CodeFile attribute instead of the Codebehind or Src attribute. Also much of the used to DataGrid properties have changed, as seen below:
|
.NET
1.1 DataGrid
|
.NET
2.0 GridView
|
|
|
CurrentPageIndex
|
-->
|
PageIndex
|
|
OnPageIndexChanged
|
-->
|
OnPageIndexChanging
|
|
OnSortCommand
|
-->
|
OnSorting
|
|
DataKeyField
|
-->
|
DataKeyNames
|
|
SelectedItemStyle
|
-->
|
SelectedRowStyle
|
|
ItemStyle
|
-->
|
RowStyle
|
|
TemplateColumn
|
-->
|
TemplateField
|
|
BoundColumn
|
-->
|
BoundField
|
|
DataGrid.Items
|
-->
|
GridView.Rows
|
|
DataGridItem
|
-->
|
GridViewRow
|
|
DataGridItem (ItemIndex)
|
-->
|
GridViewRow (RowIndex).Value
|
|
DataGridPageChangedEventArgs
|
-->
|
GridViewPageEventArgs
|
|
DataGridSortCommandEventArgs
|
-->
|
GridViewSortEventArgs
|
The CurrentPageIndex which gets or sets the index of the currently displayed page is now simply PageIndex. Setting up paging and sorting in the Gridview has changed from the OnPageIndexChanged and OnSortCommand methods to OnPageIndexChanging and OnSorting, respectively. The primary key field for the items displayed in the GridView has also changed from DataKeyField to DataKeyNames property.
Setting up row colors on the grid is no more SelectedItemStyle or ItemStyle but rather SelectedRowStyle and RowStyle. I guess this makes more sense since it is a row, anyway. The TemplateColumn class that displays custom content in a data-bound control is now TemplateField, and its partner the BoundColumn which represents a field that is displayed as text in a data-bound control is now called BoundField.
Next, in our code-behind, .NET 2.0 utilizes a new language feature known as a Partial. A Partial class is just that, a partial, incomplete definition of the class or structure. So all that is included in the partial class in only the code needed, such as event handlers and the like. .NET infers the control instances and it derives the events bound from the .aspx file during compilation. Notice in the codebehind I didn't have to declare the GridView or the OutputMsg controls there, as I did in the DataGrid version, neither did I need to include most of the Imports statements that were there before!
Another change in the framework went to the RegisterClientScriptBlock method, this now obsolete method needs to be ClientScript.RegisterClientScriptBlock (Type type, string key, string script) or in our code ClientScript.RegisterClientScriptBlock (Me.GetType(),"clientScript", jsScript.ToString()).
As for implementing custom paging, this also has changed its class wording from DataGridPageChangedEventArgs to GridViewPageEventArgs.
Also, when we retrieve the key value of each record based on DataGrids DataKeyField property we set up the loop like so:
For Each dgItem In MyDataGrid.Items
'Retrieve key value of each record based on DataGrids DataKeyField property
ChkBxIndex = MyDataGrid.DataKeys(dgItem.ItemIndex)
Next
Accomplishing the same now needs to use the GridView's DataKeyNames property and the DataGridItem's ItemIndex is now the GridViewRow's RowIndex Value:
'Loop through GridView Items
For Each dgItem In MyGridView.Rows
'Retrieve key value of each record based on GridViews DataKeyNames property
ChkBxIndex = MyGridView.DataKeys(dgItem.RowIndex).Value
Next
And aside from changing every instance of the word DataGrid to GridView, as for this article that's about it. So here's the code in its .NET 2.0 entirety, with row color state. Enjoy!
Main Page
<%@ Page Language="VB" Strict="True" Explicit="True" Buffer="True"
Debug="False" Trace="False" CodeFile="mGridView.aspx.vb"
Inherits="MultiDeleteDG.WebForm" AutoEventWireup="True"
EnableSessionState="True" %>
<html>
<head></head>
<body>
<form runat="server">
<h3>Selecting, Confirming & Deleting Multiple Checkbox Items In A GridView (i.e. HotMail & Yahoo) -<br>
Part 2: Maintaining CheckBox State Across Pages with Sorting </h3>
<br />
Current Page: <%=MyGridView.PageIndex +1%> <br />
<ASP:GridView id="MyGridView" runat="server"
Width="700"
BackColor="white"
BorderColor="black"
CellPadding="3"
CellSpacing="0"
Font-Size="9pt"
AutoGenerateColumns="False"
HeaderStyle-BackColor="darkred"
HeaderStyle-ForeColor="white"
AllowPaging="True"
AllowCustomPaging="False"
AllowSorting="True"
OnPageIndexChanging="MyGridView_Page"
OnSorting="MyGridView_Sort"
PageSize="10"
PagerStyle-Mode="NumericPages"
PagerStyle-HorizontalAlign="Right"
DataKeyNames="ID">
<SelectedRowStyle BackColor="#F5EDED" ForeColor="Black" />
<RowStyle BackColor="White" ForeColor="Black" />
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="CheckAll" OnClick="javascript: highlightChkBxRow(this);
return select_deselectAll (this.checked, this.id);" runat="server" />
<font face="Webdings" color="white" size="4">a</font>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="DeleteThis" OnClick="javascript: highlightChkBxRow(this);
return select_deselectAll (this.checked, this.id);" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="StoreID" SortExpression="ID asc" Datafield="ID" runat="server" />
<asp:BoundField HeaderText="Store" SortExpression="Company asc" Datafield="Company" runat="server" />
<asp:BoundField HeaderText="Address" SortExpression="Address asc" Datafield="Address" runat="server" />
<asp:BoundField HeaderText="City" SortExpression="City asc" Datafield="City" runat="server" />
<asp:BoundField HeaderText="State" SortExpression="State asc" Datafield="State" runat="server" />
<asp:BoundField HeaderText="Zip" SortExpression="Zip asc" Datafield="Zip" runat="server" />
</Columns>
</ASP:GridView>
<br />
<asp:Button id="Confirm" onclick="DeleteAllIds" runat="server" Text="Delete Items" />
<asp:Button id="ClearAll" onclick="ClearGridView" runat="server" Text="Clear All" />
<span id="OutputMsg" runat="server" EnableViewState="false" />
</form>
</body>
</html>
The Code-Behind
Imports System.Data
Imports System.Data.SQLClient
Namespace MultiDeleteDG
Partial Class WebForm
Inherits System.Web.UI.Page
Protected CheckBox As System.Web.UI.WebControls.CheckBox
Protected objConnect As SqlConnection
Protected myDataAdapter As SqlDataAdapter
Protected myCommand As SqlCommand
Protected DS as Dataset
Protected dgItem As GridViewRow
Public deletedIds As String = ""
Public ChkdItems As String = ""
Public SortField As String = ""
Public ChkBxIndex As String = ""
Public BxChkd As Boolean = False
Public CheckedItems As ArrayList
Public Results() As String
Sub Page_PreRender (ByVal Sender As Object, ByVal E As EventArgs)
Dim nl As String = Environment.NewLine
Dim jsScript As New StringBuilder ()
With jsScript
.Append ("<script language=JavaScript>" & nl)
.Append ("<!--" & nl & nl)
.Append ("function confirmDelete (frm) {" & nl & nl)
.Append (" // loop through all elements" & nl & nl)
.Append (" for (i=0; i<frm.length; i++) {"& nl & nl)
.Append (" // Look for our checkboxes only" & nl)
.Append (" if (frm.elements[i].name.indexOf ('DeleteThis') !=-1) {" & nl & nl)
.Append (" // If any are checked then confirm alert, otherwise nothing happens" & nl)
.Append (" if(frm.elements[i].checked) {" & nl & nl)
.Append (" return confirm ('Are you sure you want to delete your selection(s)?')" & nl & nl)
.Append (" }" & nl)
.Append (" }" & nl)
.Append (" }" & nl)
.Append (" }" & nl & nl)
.Append ("/*Using modified select_deselectAll script function of my original one,")
.Append (" from Developerfusion.com forum members - ketcapli & thombo")
.Append (" Forum Post - [http://www.developerfusion.co.uk/forums/topic-22773]*/")
.Append ("function select_deselectAll (chkVal, idVal) {" & nl)
.Append (" var frm = document.forms[0];" & nl)
.Append (" if (idVal.indexOf('DeleteThis') != -1 && chkVal == true){" & nl)
.Append (" var AllAreSelected = true;" & nl)
.Append(" for (i=0; i<frm.length; i++) {" & nl)
.Append(" if (frm.elements[i].id.indexOf('DeleteThis') != -1 &&
frm.elements[i].checked == false){ " & nl)
.Append (" AllAreSelected = false;" & nl)
.Append (" break;" & nl)
.Append (" } " & nl)
.Append (" } " & nl)
.Append (" if(AllAreSelected == true){" & nl)
.Append (" for (j=0; j<frm.length; j++) {" & nl)
.Append (" if (frm.elements[j].id.indexOf ('CheckAll') != -1) {" & nl)
.Append (" frm.elements[j].checked = true;" & nl)
.Append (" break;" & nl)
.Append (" }" & nl)
.Append (" }" & nl)
.Append (" }" & nl)
.Append (" } else {" & nl)
.Append (" for (i=0; i<frm.length; i++) {" & nl)
.Append (" if (idVal.indexOf ('CheckAll') != -1) {" & nl)
.Append (" if(chkVal == true) {" & nl)
.Append (" frm.elements[i].checked = true; " & nl)
.Append (" } else {" & nl)
.Append (" frm.elements[i].checked = false; " & nl)
.Append (" }" & nl)
.Append (" } else if (idVal.indexOf('DeleteThis') != -1 &&
frm.elements[i].checked == false) {" & nl)
.Append (" for (j=0; j<frm.length; j++) {" & nl)
.Append (" if (frm.elements[j].id.indexOf ('CheckAll') != -1) { " & nl)
.Append (" frm.elements[j].checked = false;" & nl)
.Append (" break; " & nl)
.Append (" } " & nl)
.Append (" } " & nl)
.Append (" } " & nl)
.Append (" } " & nl)
.Append (" } " & nl)
.Append (" } " & nl & nl)
.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)
.Append ("//--> " & nl & nl)
.Append ("</scr" & "ipt>")
End With
ClientScript.RegisterClientScriptBlock (Me.GetType(),"clientScript",_
jsScript.ToString())
jsScript = Nothing
Dim button As WebControl = CType(Page.FindControl("Confirm"), WebControl)
button.Attributes.Add("onclick", "return confirmDelete (this.form);")
End Sub
Sub Page_Load (ByVal Sender As Object, ByVal E As EventArgs)
objConnect = New SqlConnection("server=(local);database=Northwind;uid=sa;pwd=;")
If Not IsPostBack Then
Session.Clear()
'Set up default column sorting
If IsNothing(Session ("SortOrder")) Then
BindData ("ID asc")
Else
BindData (Session ("SortOrder"))
End If
End If
End Sub
Sub MyGridView_Page (sender As Object, e As GridViewPageEventArgs)
'Get CheckBoxValues before paging occurs
GetCheckBoxValues()
MyGridView.PageIndex = e.NewPageIndex
BindData(Session ("SortOrder"))
'Populate current GridView page with the current page items from Session after databind
RePopulateCheckBoxes ()
End Sub
Sub GetCheckBoxValues() 'As paging occurs store checkbox values
CheckedItems = New ArrayList
'Loop through GridView Items
For Each dgItem In MyGridView.Rows
'Retrieve key value of each record based on GridViews DataKeyNames property
ChkBxIndex = MyGridView.DataKeys(dgItem.RowIndex).Value
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
Sub BindData (SortField As String)
'Setup Session Cache for different users
Dim Source As DataView = Session ("dgCache")
If (IsNothing (Source)) Then
Dim sqlQuery As String = "Select OrderId As Id, ShipName As Company," _
& " ShipAddress As Address, ShipCity As City, _
ShipCountry As State, ShipPostalCode As Zip from Orders"
myDataAdapter = New SqlDataAdapter(sqlQuery, objConnect)
DS = New Dataset()
myDataAdapter.Fill(DS, "MyGridView")
'Assign sort expression to Session
Session ("SortOrder") = SortField
'Setup DataView for Sorting
Source = DS.Tables(0).DefaultView
'Insert DataView into Session
Session ("dgCache") = Source
End If
Source.Sort = SortField
MyGridView.DataSource = Source
MyGridView.DataBind ()
'Close connection
objConnect.Close
End Sub
Sub RePopulateCheckBoxes ()
CheckedItems = New ArrayList
CheckedItems = Session ("CheckedItems")
If Not IsNothing(CheckedItems) Then
'Loop through GridView Items
For Each dgItem in MyGridView.Rows
ChkBxIndex = MyGridView.DataKeys(dgItem.RowIndex).Value
'Repopulate GridView with items found in Session
If CheckedItems.Contains(ChkBxIndex) Then
CheckBox = CType(dgItem.FindControl("DeleteThis"), CheckBox)
CheckBox.Checked = True
dgItem.ForeColor = MyGridView.SelectedRowStyle.ForeColor
dgItem.BackColor = MyGridView.SelectedRowStyle.BackColor
Else
dgItem.ForeColor = MyGridView.RowStyle.ForeColor
dgItem.BackColor = MyGridView.RowStyle.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
Sub DeleteAllIds (ByVal sender As Object, ByVal e As EventArgs)
'Regrab values in case the deletion occurs on the given page and any checkboxes were unchecked
'on the current page without any postback to correct the values in Session
GetCheckBoxValues ()
If BxChkd = True Then
RePopulateCheckBoxes ()
'Delete the rows of data containing the checkbox values
Dim deleteSQL As String = "DELETE from Orders WHERE OrderId IN (" + deletedIds + ");"
myCommand = New SqlCommand (deleteSQL, objConnect)
With myCommand
.Connection.Open()
.ExecuteNonQuery()
End With
'Close connection
objConnect.Close()
OutputMsg.InnerHtml += "<font size=4><b>Store information has been deleted.</b></font>"
OutputMsg.Style("color") = "green"
'Clear all Session values
Session.Clear()
'Reset GridView to top
MyGridView.PageIndex = 0
BindData (Session ("SortOrder"))
End If
End Sub
Function SortOrder (Field As String) As String
Dim so As String = Session ("SortOrder")
If Field = so Then
SortOrder = Replace (Field,"asc","desc")
ElseIf Field <> so Then
SortOrder = Replace (Field,"desc","asc")
Else
SortOrder = Replace (Field,"asc","desc")
End If
'Maintain persistent sort order
Session ("SortOrder") = SortOrder
End Function
Sub MyGridView_Sort (Sender As Object, E As GridViewSortEventArgs)
'To retain checkbox on sorting
GetCheckBoxValues ()
MyGridView.PageIndex = 0 'To sort from top
BindData (SortOrder (E.SortExpression).ToString()) 'Rebind our GridView
'To retain checkbox on sorting
RePopulateCheckBoxes ()
End Sub
Sub ClearGridView (ByVal sender As Object, ByVal e As EventArgs)
'Clear All Session Values
Session.Clear()
'Reset GridView to top
MyGridView.PageIndex = 0
BindData ("ID asc") 'Rebind our GridView
End Sub
End Class
End Namespace
Related articles
Related discussion
-
An Introduction to VB.NET and Database Programming
by yen (12 replies)
-
Using ADO.NET with SQL Server
by jkoder59 (19 replies)
-
OLEDB Connection running like a dog.
by kruelintent (3 replies)
-
.NET Estate Agent Web Service / Website
by chr15athome (8 replies)
-
login fail to sql server with ADO.NET
by inferano (2 replies)
Related podcasts
-
CodeCast Episode 4: State of .NET, IE8, ASP.NET MVC, and O'Reilly Media
CodeCast Episode 4: State of .NET, IE8, ASP.NET MVC, and O'Reilly MediaHosts Ken Levy and Markus Egger discuss the new State of .NET events, IE8, ASP.NET MVC, followed by an interview from PDC with two editors from O'Reilly Media. More on ASP.NET MVC can be found at http://asp.net/mvc. Interview...
Events coming up
-
Dec
6
Developing AJAX Web Applications with Castle Monorail
London, United Kingdom
Monorail is the model-view-controller engine of the Castle Project, bringing many of the best ideas of Ruby on Rails to the .NET world. In this talk, David De Florinier and Gojko Adzic show how Monorail makes it easy to develop .NET based AJAX applications, and how to use the Castle Project to build Web 2.0 applications effectively. Come to this session if you are a .NET web developer. Everyone is welcome!
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
sir,I am new to this gridview.I want to delete checked rows from my database.In the grid view i have 4 columns,and compan name is the first column.I want to take the value of the company name column and use it in delete query.I am using the following code,but after executing the line string cname=row.cells[0].text,cname is showing the null value.Why?
my code under delete buttonclick event is this
foreach(GridViewRow row in ExpSummaryGrid.Rows)
{
string cname = row.cells[0].text;
string del = "delete from expsummary 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, "expsummary");
}
}
Do you have the C# version of this code somewhere? I just came across this situation with check boxes and paging. I'm using VS2005C# and my code has check boxes on each row and I'm iterating thru them to check if they are checked but if you select a few on the first page and them switch to the second page of the gridview then switch back the gridview loses what items are checked. I could use some help converting your VB into C# 2005.
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."
You see, Dimitros,
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
Hello all,
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.