Cascading Gridviews and Check All header cell

3 posts, 0 answers
  1. Chris
    Chris avatar
    59 posts
    Member since:
    Jun 2012

    Posted 22 Feb 2012 Link to this post

    Hi,
    I have implemented the 'Check All Header Cell' as shown in this KB article http://www.telerik.com/support/kb/winforms/gridview/add-check-uncheck-all-check-box-in-the-header-cell.aspx.

    This works really well in most scenarios but I have run into a small bump in the road. The problem is that I have two grids that are linked in a cascading style. The purpose of this is to fill grid 2 with all of the contacts relating to the selected person or people in grid 1. Again this is all working perfectly for single or multiple selections using the normal check boxes in the rows.

    I am hooking in to the ValueChanged event and then checking the cell type to determine if it is a single or check all operation. I set a processing flag to avoid multiple runs of the population code. The flag is reset in the DataBindingComplete event.

    private void PupilGrid_ValueChanged(object sender, EventArgs e)
            {
                //set a processing flag as if the select all checkbox is used this
                //event fires for every checkbox in the column!
                if (_populatingParentGrid) return;
     
                _populatingParentGrid = true;
     
                if (sender.GetType() == typeof(GridViewCellInfo))
                {
                    //this means the select all box has been checked
                    RefreshParentGrid(true);
                }
                else if (sender.GetType() == typeof(RadCheckBoxEditor))
                {
                    //single box checked
                    RefreshParentGrid(false);
                }
            }
     
    private void ParentGrid_DataBindingComplete(object sender, GridViewBindingCompleteEventArgs e)
            {
                //reset processing flag
                _populatingParentGrid = false;
                //PupilGrid.Enabled = true;        }

    The problem I am getting is that the databinding is so fast that the flag is reset almost instantly. The 'Check All' code from the KB article  works by setting each checkbox to checked in a loop. This is firing the ValueChanged event and running the Grid 2 population code over and over again resulting in a lengthy delay (30 secs +) when the header cell is clicked.

    I need a way to notify my app that the 'Check All' operation has finished (that is all of the check boxes have had their state changed and there are no other ValueChanged events to be raised). The following method from CheckBoxHeaderCell.cs is where I would expect see an event being raised from, but I cannot figure out a way to hook such an event from my app or make it bubble up via the grid.

    private void checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args)
            {
                if (suspendProcessingToggleStateChanged) return;
                bool valueState = false;
     
                if (args.ToggleState == ToggleState.On)
                {
                    valueState = true;
                }
                GridViewElement.EditorManager.EndEdit();
                TableElement.BeginUpdate();
     
                foreach (GridViewRowInfo t in ViewInfo.Rows)
                {
                    t.Cells[ColumnIndex].Value = valueState;
                }
     
                TableElement.EndUpdate(false);
     
                TableElement.Update(GridUINotifyAction.DataChanged);
     
                //Need to raise an event here to say that the processing has finished
            }

    I add the column to my grid using the following code, I have checked the events available to 'checkColumn' and there is nothing suitable that I can see.

    private void AddCheckColumn()
           {
               //Telerik code - see above for link
               var checkColumn = new CustomCheckBoxColumn {Name = "Select", HeaderText = "All", ReadOnly = false};
               //No suitable events found here
               PupilGrid.Columns.Insert(0, checkColumn);
               var checkColumn2 = new CustomCheckBoxColumn {Name = "Select", HeaderText = "All", ReadOnly = false};
               ParentGrid.Columns.Insert(0, checkColumn2);
           }


    Can you please let me know if there is a way to raise an event from this custom header cell that can be hooked into by my app.

    Many Thanks

    Chris

  2. Chris
    Chris avatar
    59 posts
    Member since:
    Jun 2012

    Posted 23 Feb 2012 Link to this post

    Hi,
           I have found a solution / workaround, not sure if it is the best way but it seems to work. Within CheckBoxHeaderCell.cs I added the following event code and then added a call to raise the event after all of the checkboxes had been checked / unchecked.:

    public event EventHandler SelectAllComplete;
     
            public void OnSelectAllComplete(EventArgs e)
            {
                     //Could be improved with custom event args for the checkbox value
                EventHandler handler = SelectAllComplete;
                if (handler != null) handler(this, e);
            }
     
    private void checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args)
            {
                if (suspendProcessingToggleStateChanged) return;
                bool valueState = false;
     
                if (args.ToggleState == ToggleState.On)
                {
                    valueState = true;
                }
                GridViewElement.EditorManager.EndEdit();
                TableElement.BeginUpdate();
     
                foreach (GridViewRowInfo t in ViewInfo.Rows)
                {
                    t.Cells[ColumnIndex].Value = valueState;
                }
     
                TableElement.EndUpdate(false);
     
                TableElement.Update(GridUINotifyAction.DataChanged);
     
                //Need to raise an event here to say that the processing has finished
                OnSelectAllComplete(new EventArgs());
     
            }

    To create an event handler for this event I had to do some digging and I found in the end the ViewCellFormatting event (not the CellFormatting event) seems to have everything in it that I needed. I did try CreateCell but the CellElement is always null, this is to do with the virtualisation used by the grid if I understand the other KB articles.

    So by using this event to create an event handler in the parent form I have been able to successfully hook the SelectAllComplete evnt of the header cell and run my child grid population code once only. 

    private void PupilGrid_ViewCellFormatting_1(object sender, CellFormattingEventArgs e)
           {
               if (e.CellElement.GetType() == typeof(CheckBoxHeaderCell))
               {
                   var cell = e.CellElement as CheckBoxHeaderCell;
     
                   //remove event and then re-add this will ensure that the event is only added once - might not be needed ?
                   cell.SelectAllComplete -= new EventHandler(cell_SelectAllComplete);
                   cell.SelectAllComplete += new EventHandler(cell_SelectAllComplete);
               }
           }

    I then moved my refresh code to the new event handler and it is now run exactly once.

    void cell_SelectAllComplete(object sender, EventArgs e)
           {
    //moved from ValueChanged event
               RefreshParentGrid(true);
           }


    The cascading grids now work perfectly. If there is a better event to use please let me know, otherwise this might be worth adding to the sample as I can;t be the only person looking to do this sort of thing.

    Thanks

    Chris
  3. Svett
    Admin
    Svett avatar
    728 posts

    Posted 27 Feb 2012 Link to this post

    Hi Chris,

    I recommend using the built-in events to achieve that. You can raise the ValueChanged event instead of your SelectAllComplete event in the following way:

    this.TableElement.MasterTemplate.EventDispatcher.RaiseEvent(EventDispatcher.ValueChanged, this, EventArgs.Empty);

    Then you will not need to use CellFormatting event. You can simply subscribe to the ValueChanged event of RadGridView, where you can handle your logic in this way:
    private void radGridView1_ValueChanged(object sender, EventArgs e)
    {
        CheckBoxHeaderCell headerCell = sender as CheckBoxHeaderCell;
     
        if (headerCell != null)
        {
            // PERFORM YOUR LOGIC SYNC LOGIC HERE
        }
    }

    I hope this helps.

    All the best,
    Svett
    the Telerik team
    RadControls for WinForms Q1'12 release is now live! Check out what's new or download a free trial >>
Back to Top