This is a migrated thread and some comments may be shown as answers.

CheckBoxColumn with CheckBox Header

17 Answers 416 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Morgan McCollough
Top achievements
Rank 1
Morgan McCollough asked on 01 Sep 2010, 08:29 PM
I am a little confused. I have a grid with a column containing a boolean value. I have the checkbox column working with a single click, based on info from other forum posts. However, I am now trying to put a checkbox in the header to toggle that column for all visible rows. I implemented a click handler for that header checkbox to loop through cells in that column and click the checkbox, but it doesn't seem to work. Odd things happen like occasionally the last visible item will change, or sometimes some other seemingly random cell will become highlighted. Below is the basic code for the handler. Am I approaching this completely wrong? I wanted to do it at the UI level because I wanted all of my boolean columns to behave this way and didn't want to do it at the data level because I would have to basically provide a different implementation in every different grid.

<telerikGrid:GridViewCheckBoxColumn DataMemberBinding="{Binding Path=ActiveFlag}" IsVisible="False" AutoSelectOnEdit="True" IsThreeState="False">
    <telerikGrid:GridViewCheckBoxColumn.Header>
        <CheckBox Content="Active" Click="HeaderCheckBox_Click" IsThreeState="False" />
    </telerikGrid:GridViewCheckBoxColumn.Header>
</telerikGrid:GridViewCheckBoxColumn>

private void HeaderCheckBox_Click(object sender, RoutedEventArgs e)
        {
            CheckBox cb = (CheckBox)sender;
            GridViewHeaderCell header = cb.ParentOfType<GridViewHeaderCell>();
 
            ReferenceGrid.BeginEdit();
            foreach (GridViewRowItem item in ReferenceGrid.ChildrenOfType<GridViewRowItem>())
            {
                foreach (var cell in item.Cells)
                {
                    if (cell.Column == header.Column)
                    {
                        if (cell is GridViewCell)
                        {
                            GridViewCell c = (GridViewCell)cell;
                            c.BeginEdit();
                            CheckBox checkbox = c.GetEditingElement() as CheckBox;
                            if (checkbox != null)
                                checkbox.IsChecked = cb.IsChecked;
                            c.CommitEdit();
                        }
                        break;
                    }
                }
            }
            ReferenceGrid.CommitEdit();
        }

17 Answers, 1 is accepted

Sort by
0
Maya
Telerik team
answered on 02 Sep 2010, 01:28 PM
Hi Morgan McCollough,

RadGridView enables virtualization by default and as a result when working directly with the UI elements (in your case when checking/unchecking CheckBoxes), this may result in unexpected for the end-user behavior. Meaning that some of the checked CheckBoxes may become unchecked and vise versus. That is why the recommended way is to use data items, for example you may expose a new property responsible for the state of those Check Boxes. 
Another possible approach, depending on your requirements, may be to use RadGridView's GridVewSelectColumn
If none of those is helpful for your application, please share more details about your requirements and project's settings, so that I can provide with a more suitable solution or a sample project if needed.


Sincerely yours,
Maya
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Morgan McCollough
Top achievements
Rank 1
answered on 03 Sep 2010, 01:01 AM
I could experiment with the Select Column, but I suspect that I would have to do something like break the binding programmatically. The reason I was not using that is that the column is bound to a boolean value that has nothing to do with selection. The boolean is just an indicator that a particular product item has been purchased.
0
Maya
Telerik team
answered on 03 Sep 2010, 10:29 AM
Hi Morgan McCollough,

If you want the CheckBox in the Column's Header just to mark all the items in the grid as "Purchased" for example, you may loop through all the items and set their property "IsPurchased" to "true". 
For example:

private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {
            CheckBox headerCheckBox = e.OriginalSource as CheckBox;
            if(headerCheckBox.IsChecked == true)
            {
                foreach(Player item in this.playersGrid.Items)
                {
                    item.IsActive = true;
                }
            }
        }

Another possibility may be to create your custom column implementing the functionality you want as described in this blog post.


Sincerely yours,
Maya
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Morgan McCollough
Top achievements
Rank 1
answered on 10 Sep 2010, 06:54 PM
Thanks for the suggestion. I went ahead and tried the custom column, because there are other boolean properties in other grids that I would like to do the same thing with, and I wanted to avoid writing specific code-behind handlers on each one. Anyway, I tried the example in the blog post and used the following code, but the binding doesn't seem to work in TwoWay mode. The value seems to come up write when the grid is loaded, but the underlying property does not change when I click the checkbox (the DataMemberBinding in the xaml is indeed set to TwoWay). Any idea what might be going on here?

BTW, I am on build 2010.2.812.1040.

public override FrameworkElement CreateCellElement(Telerik.Windows.Controls.GridView.GridViewCell cell, object dataItem)
        {
            var cb = cell.Content as CheckBox;
 
            if (cb == null)
            {
                cb = new CheckBox();
                cb.IsThreeState = false;
                cb.SetBinding(CheckBox.IsCheckedProperty, this.DataMemberBinding);
                cell.Content = cb;
            }
 
            return cb;
        }
 
        public override FrameworkElement CreateCellEditElement(Telerik.Windows.Controls.GridView.GridViewCell cell, object dataItem)
        {
            var cb = cell.Content as CheckBox;
 
            if (cb == null)
            {
                cb = new CheckBox();
                cb.IsThreeState = false;
                cb.SetBinding(PmcCheckBox.IsCheckedProperty, this.DataMemberBinding);
                cell.Content = cb;
            }
 
            return cb;
        }

0
Maya
Telerik team
answered on 13 Sep 2010, 08:48 AM
Hello Morgan McCollough,

I am senidng you a sample project illustrating how to create a custom CheckBoxColumn. It simulates the behavior of a GridViewSelectColumn with the difference that it is bound to a specific property but not to IsSelected property of the GridViewRow. You may use it as a reference and change it so that it reponds to your requirements. 
In case you have any further questions or difficulties, do not hesitate to get back to us.
 

All the best,
Maya
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Morgan McCollough
Top achievements
Rank 1
answered on 14 Sep 2010, 05:06 PM
Thanks very much for the example. I hadn't thought to use the Expression library in writing the function to toggle the value in all the rows.

Unfortunately, I still ran into some minor issues with the project you sent. I noticed that the XAML in the project didn't reference the new custom column, and once I changed that the example project basically had the same issues I had been seeing in my app. When the page first loads the checkboxes have the correct state, and you can toggle all of them using the header checkbox. However, once you change the state of one of the checkboxes in the grid, it seems to lose the binding or something and the header checkbox will no longer affect the state of the one that you have clicked. Does that make sense?

I tried augmenting the custom column code you sent by adding an implementation for CreateCellEditElement that was practically identical to the CreateCellElement implementation. When I did this there were odd COM exceptions being thrown when I clicked on a checkbox in any one row. The only thing I could get to work to my satisfaction was using a DataTemplate (see below). I'm not sure how this was different than just implementing those 2 methods, but it seems to work.

I also added an AutoRowEditBehavior that would cause the checkbox to be toggled automatically when the cell is clicked in order to get around that issue of having to click multiple times in order to toggle a checkbox in a grid row.

protected override void OnDataMemberBindingChanged()
        {
            base.OnDataMemberBindingChanged();
            if (this.DataMemberBinding == null)
                return;
            // Use a data template, because overriding the 2 create element functions like normal seems to cause odd problems when trying to make the checkbox editable with a single click
            StringBuilder sb = new StringBuilder();
            sb.Append("<DataTemplate ");
            sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
            sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
            sb.AppendFormat("<CheckBox IsChecked='{{Binding Path={0}, Mode=TwoWay}}' HorizontalAlignment='Center' IsThreeState='False' />", this.DataMemberBinding.Path.Path);
            sb.Append("</DataTemplate>");
            var dt = (DataTemplate)XamlReader.Load(sb.ToString());
            this.CellTemplate = dt;
            this.CellEditTemplate = dt;
        }

0
Morgan McCollough
Top achievements
Rank 1
answered on 14 Sep 2010, 05:52 PM
Scratch that. I am not sure where that COM exception was coming from (I can't reproduce it). Also, I think I was wrong about that binding getting disconnected. I think I just confused myself on that, because the column I was looking at only had a OneWay binding set.

The problem that is happening is if I override those 2 methods, I get a value outside of expected range exception when I expand the row details and then click the checkbox in the row. The exception seems to occur when BeginEdit is called as part of the AutoRowEditBehavior. Note that this does NOT happen if I use a DataTemplate as outlined above.
0
Maya
Telerik team
answered on 20 Sep 2010, 11:15 AM
Hi Morgan McCollough,

Firstly, please excuse me for the late response. 
I am sending you the sample project with some changes made so that it is a bit clearer and more applicable. Mainly, what needs to be done is to set the Mode of the Binding for that custom column to "TwoWay".
Please let me know if it helps. In case it does not, I would need more information about your application and its settings. It would be great if it is possible to send me a sample project with your exact requitements via support ticket. 
 

Sincerely yours,
Maya
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Morgan McCollough
Top achievements
Rank 1
answered on 21 Sep 2010, 05:35 PM
I got the TwoWay binding working. That was definitely my mistake. Thanks for the updated example, but my column still suffers from the same out of range exception unless I implement it using the template method I mentioned.

Also, when I try using your method the binding doesn't seem to cause the underlying data to change in my app even though it seems to in yours. I think it has to do with the edit mode or selection mode (I am using cell selection), because I can't find any other real differences between your example and mine other than the fact that I am using the 8/12 build. I do notice in both my grid and yours that when you click in the cell but outside the checkbox itself, it seems to put the cell in edit mode and the checkbox gets smaller as if it is a different rendered control.

The upshot is that I have this mostly working, but I had to use the template method and an Auto-edit behavior to put the cell in edit mode during the MouseLeftButtonDown event.

I don't suppose there is a way to just put the cell perpetually in edit mode when using a checkbox?
0
Maya
Telerik team
answered on 24 Sep 2010, 12:52 PM
Hi Morgan McCollough,

I have tested my sample project and the underlaying data is updated as expected, no matter of the edit mode or the selection unit. As for the skipping the visual state of edit mode of that custom column, you may set its property IsReadOnly to "True". I am sending you the updated sample project that introduces that setting and defines a RowDetailsTemplate. 


Kind regards,
Maya
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Anthony
Top achievements
Rank 2
answered on 24 Aug 2011, 04:00 AM
Hello, can I have this sample project of yours in VB.Net? I have converted it using the telerik Code Converter but there are some parts of codes I cant understand.

Any help would be appreciated. Thanks.
0
Maya
Telerik team
answered on 24 Aug 2011, 07:13 AM
Hi Mark,

May you shed some more light on the exact problems you encountered so that we could concentrate on them right away ? Is there any particular part of the code that you cannot convert ? 


Kind regards,
Maya
the Telerik team

Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's DevProConnections Awards. We are competing in mind-blowing 20 categories and every vote counts! VOTE for Telerik NOW >>

0
Anthony
Top achievements
Rank 2
answered on 24 Aug 2011, 07:28 AM
It will be a waste of time for me fixing the converted code Maya. Would it be possible to get the VB.Net version of the code posted here in this thread?

Anyway, here is my scenario... I have a RadGridView with row details, I have a field "isChecked" as boolean that binds in a checkbox, this field will determine who is the checked items then it will mark the data to 'true' when selected. Now, I am able to do that scenario... The thing is, I also added checkbox for the header template... The main problem is that the checkbox header is not firing an event. I would like to fire an event because I want to collect all those items that is marked "isChecked =  True"

Kindly help me with this matter... Thanks.
0
Chen
Top achievements
Rank 1
answered on 20 Apr 2012, 05:47 PM
Hi Maya,

I tried your code and got the "{System.StackOverflowException}" exception at the setter of the "Header" property in the "CustomCheckBoxColumn.cs" file. Do you have any idea?

By the way, I included this customized checkbox column in the "telerik:GridViewColumnCollection" tag in the "UserControl.Resources" of the xaml file as following:
<UserControl.Resources>        
    <telerik:GridViewColumnCollection x:Name="CustomColumnDefinition">            
        <my:CustomCheckBoxColumn DataMemberBinding="{Binding IsChecked, Mode=TwoWay}" IsReadOnly="True" />            
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=otherproperty1}" Header="Resource Name" />           
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=otherproperty2}" Header="Resource Description"/>          
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=otherproperty3}" Header="IPType" />       
    </telerik:GridViewColumnCollection> 
</UserControl.Resources>

Thanks for any suggestions.

Some suggestions:
  1. In you sample code, I'd like to see the functions of :

          a. If all the checkboxes in the column are checked, the checkbox in the header cell should be checked as well
          b. If any of the checkboxes in the column is/are unchecked, the checkbox in the header cell should be unckecked if it is checked.

2.    In the "SelectOrDeselectAllItems" method in the "CustomCheckBoxColumn.cs" file, if you change the "Player" type in the foreach loolp to "var", this class can be used for any types.

 

SelectOrDeselectAllItems

0
Maya
Telerik team
answered on 21 Apr 2012, 10:10 AM
Hi Chen,

You can subscribe to the Checked event of the CheckBox in CreateCellElement method and verify whether all items in the Items collection have the corresponding property set to "true". Once you confirm that all of them are 'True', you can set IsChecked of the Header CheckBox to "true". The same approach could be used in the reverse case - in the Checked event handler, if a single item's property is set to 'false', set header's CheckBox to 'false'.
Considering the second requirement, I am not quite sure what is the question here. Did you not managed to implement the code for different than 'Player' type ?  

Regards,
Maya
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Chen
Top achievements
Rank 1
answered on 23 Apr 2012, 01:53 PM
Hi Maya,

Thanks for the reply.

Did you have any suggestions about the "{System.StackOverflowException}" exception?
This is my top priority concern.

Thanks.
0
Maya
Telerik team
answered on 23 Apr 2012, 02:06 PM
Hello Morgan,

The thing is that I could not get the exception you mentioned. Is there anything more specific that you do in order to get it ? Why do you need such column collection defined in the Resources section ?   

Greetings,
Maya
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

Tags
GridView
Asked by
Morgan McCollough
Top achievements
Rank 1
Answers by
Maya
Telerik team
Morgan McCollough
Top achievements
Rank 1
Anthony
Top achievements
Rank 2
Chen
Top achievements
Rank 1
Share this question
or