Welcome to Tech-Review.Org Sign in | Join | Help

.net_2.0

My coding blog entries. Typically will either be more complex coding examples or overcoming product issues / troubleshooting resolutions.
Gridviews: Select / De-Select all Records without Javascript using Checkbox in Header

8 hours of combing through blogs, forum posts and books to find a spcific answer to a specific problem.  You see it all the time on sites like Yahoo Mail, where there is a convienent checkbox in the the header of a table / gridview that selects or de-selects all checkboxes in the column.  And, it is easy to do in a non-Ajax enviroment where you just inject Javascript to perform the selection and de-selection.  QuiteBut I have a problem and that entails the fact I have yet to get any JavaScript functions that worked prior to .Net's Ajax (any flavor of build - beta, RC , RTM).... to work within Microsoft's Ajax enviroment without all kinds of unexpected and application breaking behavior.

 

So, I try to do things in code-behind for the portions of my application where I am ok without the callbacks to the server understanding it is not the proper coding technique for a truly performant app (which entails making the client do all the work whenever possible). However - I will also state that I do prefer to have the server-side code handle most of the UI especially when dealing with data that may be presented which allows different users assigned specific roles to a certain records but may be able to view all of them (Think publishing approval routines or 'work flow' items).

 

The Gridview provides sorting and the ability to embed controls in between the <HeaderTemplate> opening and closing tags. Typically the header would provide the ability to display dynamic text lables and when sorting is configured properly - clickable headers that provide column sorting.

 

In most scenario's a <asp:CheckBox /> would be embedded in the <HeaderTemplate> tag and the "OnClick" event would be configured to call a function in the script to select or de-select the checkboxes in the column. But, with the need to be able to check rows and various requirements just selecting all would not be feasible...just how do you asynchronously postback to the server to handle all of that. 

 

Issue before starting out:

1. You can not just add event handlers to controls in the a GridView's header. Must work with checkbox events for onclick or onchange.

2. Whatever is implemented must not perform a full postback and disrupt the UI experience.

Preface:

This article is written from my attempts to make this work with Microsoft's Ajax.  Therefore you will undoubtedly run across some of my frustrion developing - that would not occur in programming without Ajax. 

Let's go:

 In my enviroment I am dealing with multiple update panels, a gridview and a modalpopup form.  Searching on entries on this blog will detail some of the previous programming issues I have encountered.  However, after the official release of Microsoft Ajax 1.0 - most of the coding issues finally were resolved.  With some exceptions:

 

Beware the UpdateProgress control:

 

I hate to say it - but the blog entry spells it out - it worked in RC versions getting the UpdateProgress's set image and setting source urls in code-behind.  However, I set the timeouts liberally and simply never bothered to test it with the RTM version and it kinda bit me. As a result there may be some inaccurancies in this particular entry describing the steps I went through - however my end result is tested with removing the fore-mentioned issues out of the equation...

 

The <asp:CheckBox> is not a solution for inserting in the headerstyle tags.  The reason why is how it spans inserting attributes.  The following describes this a bit more:

 

Scenario:

 

UpdatePanel that contains Gridview.

The first column is configured to have checkboxes for selecting or de-selecting.  A checkbox is added to the the header as such:

<Columns>

<asp:TemplateField    ItemStyle-Width="8px"  >
    <HeaderTemplate>

<asp:CheckBox ID="chkSelectAll" CausesValidation="false" runat="server" />

</HeaderTemplate>

<asp:CheckBox  id="chkSelect"   Width="8px"  runat="server"  /> 

</ItemTemplate></asp:TemplateField>

In code-behind -

        protected virtual void GridView_RowDataBound(Object s, GridViewRowEventArgs e)
        {
           
            if (e.Row.RowType == DataControlRowType.Header)
            {
              
                CheckBox chkSelectAll = (CheckBox)e.Row.FindControl("chkSelectAll");
                if (chkSelectAll != null)
                {

                   NOTE: autopostback true or false does not matter if a postbackreference is set.  Other buttons etc I can assign the postback reference and get asynch postbacks.  The only time the checkbox does not invoke

                   the full postback is when no postback onclick is registered and autopostback = false, but then the selection has to be read on the next asynch postback invoked.


                  // chkSelectAll.AutoPostBack = true;
      //unremark to test checkbox is found
                    //chkSelectAll.Checked = true;
                    chkSelectAll.Attributes.Add("onClick", SM.Page.ClientScript.GetPostBackEventReference(this, "SelectAll"));
                    //SM.RegisterAsyncPostBackControl(chkSelectAll);
              
                }
            }

It does execute when checked in the header - however does a FULL PAGE POSTBACK / RELOAD just like what would occur in normal postback scenarios (the screen clears and page reloads with all checked or de-selected).

However:

 

 

<Columns><asp:TemplateField    ItemStyle-Width="8px"  >
    <HeaderTemplate>

<asp:LinkButton CommandName="SelectAll"  Text="Sel" CommandArgument="SelectAll"  ID="lnkSelectAll"  runat="server" CausesValidation="false" >

</asp:LinkButton></HeaderTemplate>

 

 

The LinkButton works just fine and asynch postback occurs as intended.  I could always do a imagebutton and mimic the checkbox by changing a image to show a checked box or empty box but this is not really desired as it is a bit of a hack. Why I am not using onclick and executing javascript function to do the selection / de-select.  not all records may be able to be selected for processing and therefore I need to be  handle this in code-behind.

I do not believe this is expected behavior with the Checkbox (or rather should not be the behavior) - and of all things should not be doing a full postback when wrapped into a UpdatePanel.  Is this a Bug or am I missing something pointingly obvious...

So what is the work around? Code Example:

 Using the HtmlInputCheckBox instead.  The catch is not using the onchange event of the input checkbox.  The reason being is that IE doesn't respond to the onchange event unless something else occurs on the page afterwards.

 

1. Set the Gridview to EnableSorting = true. (Update: Not Required - it will work without it being set (or false)).

2. In the header you want the checkbox here is the code:

 

<asp:TemplateField    ItemStyle-Width="8px"  >
    <HeaderTemplate><input id="chkSelectAll"  runat="server" type="checkbox" name="chkSelectAll" /></HeaderTemplate>
    <ItemTemplate>
<asp:CheckBox  id="chkSelect"   Width="8px"  runat="server"  /> 

3. Add to the Gridview Rows Data Bind Event:

        override protected void GridView_RowDataBound(Object s, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.Header)
            {
                HtmlInputCheckBox chkSelectAll = (HtmlInputCheckBox)e.Row.FindControl("chkSelectAll");
                if (chkSelectAll != null)
                {

                    string js = SM.Page.ClientScript.GetPostBackEventReference(chkSelectAll, "selectall");
                    chkSelectAll.Attributes.Add("onclick", js);

                    SM.RegisterAsyncPostBackControl(chkSelectAll);
                }
                else
                {
                    Context.Trace.Warn("***ChkSelectAll was null");
                }

            }

4. Add to the Row_Click Event:

 protected virtual void Row_Click(Object s, GridViewCommandEventArgs e)
        {
            EnsureChildControls();
 
            if (e.CommandName.ToUpper() == "SELECTALL")
            {
                bllLogging.RecordMessage("GRIDVIEWMODAL: RaisePostBackEvent w SelectALL" + "Selected Row Index = ", "grdDataing", Severity.Severe, LoggingID + "- GridViewModal", "Bummer");

                CheckAll();
            }

        }

5. Here is what I use for the Check All:

 void CheckAll()
        {
            Context.Trace.Warn("***********At Select CHECK All Event Value before was" + isChecked.ToString());

            //CheckBox chkSelectAll = (CheckBox)grdData.FindControl("chkSelectAll");
            if (isChecked == false)
            {
                isChecked = true;

            }
            else
            {
                isChecked = false;
            }
            Context.Trace.Warn("***********At Select CHECK All Event and ischecked is " + isChecked.ToString());
            foreach (GridViewRow i in grdData.Rows)
            {
                CheckBox chkSelect = (CheckBox)i.FindControl("chkSelect");
                if (chkSelect != null && isChecked == true)
                {
                    Context.Trace.Warn("***********At True Select Event and ischecked is " + isChecked.ToString());

                    chkSelect.Checked = true;
                }
                else
                {
                    Context.Trace.Warn("***********At False Select Event and ischecked is " + isChecked.ToString());

                    chkSelect.Checked = false;
                }

            }


        }

Note use viewstate to handle the isChecked variable as such:

  [Browsable(false)]
        public bool isChecked
        {
            get
            {
                if (ViewState["isChecked"] == null)
                    return false;
                else
                    return Convert.ToBoolean((string)ViewState["isChecked"]);

            }

            set { ViewState["isChecked"] = value.ToString(); }
        }

 

The end result with those lines of code should be the ability to embed a checkbox into the header - and have it select and deselect the rows serverside.  The code provided is base code so you can add additional checks on rows to determine if they get selected etc....

 

If this code does not execute properly on your system then you have bigger troubleshooting issues being masked.  While I can not go into every detail, I have found delegates when null but no checks for null were made get masked by the SM but still create the error and corrupt the DOM.  Missing images and any other myriad of issues can be resultant.  Typical symptoms will be the GridView Dissapears, the control just does not load, or the control loads but but none of the dropdowns and other 'events' fail to fire, gridview paging shows all records even though paging is set etc...

 

The example code works on FF 2.0 and IE &.

 

 

 

Posted: Monday, February 05, 2007 6:47 PM by Jody
Filed under: , ,

Comments

Jignesh Vyas said:

Add to the Row_Click Event: ??

for which control do i add this event and how ??

# March 22, 2007 3:32 AM
New Comments to this post are disabled