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

Multi select of groups

3 Answers 207 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Maarten
Top achievements
Rank 1
Maarten asked on 06 Aug 2012, 08:58 AM
Hi All,

Our application contains a grid that allows grouping and multi select. Upon entering the screen the groups are collapsed. Our client wants to be able to select on or more groups and all it's child records by clicking on the group(s) without expanding them.

I achieved this behaviour via the following event handlers:
SelectionResultRadGridView.ViewRowFormatting += SelectionResultRadGridViewViewRowFormatting;
SelectionResultRadGridView.CellClick += SelectionResultRadGridViewCellClick;

The first event is used to change the row color of a group in case one of its child records is selected:
private static void SelectionResultRadGridViewViewRowFormatting(object sender, RowFormattingEventArgs e)
{
if (e.RowElement.RowInfo is GridViewGroupRowInfo && e.RowElement.RowInfo.ChildRows.Any(x => x.IsSelected))
{
e.RowElement.DrawFill = true;
e.RowElement.BackColor = Color.FromArgb(255,216,132);
e.RowElement.GradientStyle = GradientStyles.Solid;
}
else
{
e.RowElement.ResetValue(LightVisualElement.DrawFillProperty, ValueResetFlags.Local);
e.RowElement.ResetValue(LightVisualElement.BackColorProperty, ValueResetFlags.Local);
e.RowElement.ResetValue(LightVisualElement.NumberOfColorsProperty, ValueResetFlags.Local);
e.RowElement.ResetValue(LightVisualElement.ForeColorProperty, ValueResetFlags.Local);
}
}

the second event i use to select all child rows in case a group was selected (this currently works only in case of on level of grouping) and i always invalidate all rows to make sure that the formatting event is triggered for all groups (for instance a child row is selected i want the color of the group to change aswell)
void SelectionResultRadGridViewCellClick(object sender, GridViewCellEventArgs e)
{
if (e.Row.RowElementType == typeof(GridGroupHeaderRowElement))
{
foreach (var childRow in e.Row.ChildRows)
{
childRow.IsSelected = true;
}
}
foreach (DataGroup group in SelectionResultRadGridView.Groups)
{
group.GroupRow.InvalidateRow();
}
}

The problem however with this approach is that the shift option for multi select is not supported. A user can now select multiple groups with the ctrl button but not with the shift button. Somebody any idea? Other ideas to implement such a behaviour?

Many thanks!

Maarten

3 Answers, 1 is accepted

Sort by
0
Svett
Telerik team
answered on 08 Aug 2012, 03:04 PM
Hi Maarten,

Thank you for writing.

You have implemented your scenario to support single selection. Nevertheless, I recommend you to create a custom group row that will handle the multiselection case:
public class MyGridViewGroupRowInfo : GridViewGroupRowInfo
{
    public MyGridViewGroupRowInfo(GridViewInfo viewInfo, DataGroup group)
        : base(viewInfo, group)
    {
 
    }
 
    public override AllowedGridViewRowInfoStates AllowedStates
    {
        get
        {
            return base.AllowedStates | AllowedGridViewRowInfoStates.Selected;
        }
    }
 
    protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool val
    {
        bool result = base.SetBooleanProperty(propertyName, propertyKey, value);
 
        if (propertyName == "IsSelected")
        {
            bool isSelected = this.IsSelected;
 
            foreach (GridViewRowInfo row in this.ChildRows)
            {
                row.IsSelected = isSelected;
            }
        }
 
        return result;
    }
}

Then you should replace the default instance by using the CreateRowInfo event:
private void radGridView1_CreateRowInfo(object sender, GridViewCreateRowInfoEventArgs e)
{
    GridViewGroupRowInfo groupRow = e.RowInfo as GridViewGroupRowInfo;
 
    if (groupRow != null)
    {
        e.RowInfo = new MyGridViewGroupRowInfo(e.ViewInfo, groupRow.Group);
    }
}

You should remove the CellClick event handle approach.

I hope this helps.

Kind regards,
Svett
the Telerik team
RadControls for WinForms Q2'12 release is now live! Check out what's new or download a free trial >>
0
Maarten
Top achievements
Rank 1
answered on 09 Aug 2012, 01:26 PM

Hi Svett,

Many thx for your reply!

Based on it I extended the code and also added a custom data row class. Since the group should also be selected if a child (data row) is selected. But since a group can be included in another group i added the recursive call...

See below for the custom row classes. But now I get a ([5832]System.Threading.ThreadExceptionEventArgs)  when the grid has two or more levels of groups and i select a group with one row and after that I deselect the row.

Any ideas to solve this?

using System.Linq;
using Telerik.WinControls.UI;
 
namespace Controls
{
    class MultiSelectGroupRowInfo : GridViewGroupRowInfo
    {
        public static bool GroupSilentUpdate;
        public static bool ParentSilentUpdate;
        public MultiSelectGroupRowInfo(GridViewInfo viewInfo, DataGroup group) : base(viewInfo, group) { }
 
        public override AllowedGridViewRowInfoStates AllowedStates
        {
            get
            {
                return base.AllowedStates | AllowedGridViewRowInfoStates.Selected;
            }
        }
 
        protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool value)
        {
            bool result = base.SetBooleanProperty(propertyName, propertyKey, value);
 
            if (propertyName == "IsSelected" && !MultiSelectGroupedRowInfo.ChildSilentUpdate && !ParentSilentUpdate)
            {
                bool isSelected = IsSelected;
 
                GroupSilentUpdate = true;
 
                SelectGroupHierachy(isSelected);
                foreach (GridViewRowInfo row in ChildRows)
                {
                    row.IsSelected = isSelected;
                }
                GroupSilentUpdate = false;
            }
            return result;
        }
 
        private void SelectGroupHierachy(bool select)
        {
            ParentSilentUpdate = true;
            SelectGroup(this, select);
            ParentSilentUpdate = false;
        }
 
        private static void SelectGroup(GridViewRowInfo gridViewRowInfo, bool select)
        {
            if (gridViewRowInfo.Group != null)
            {
                GridViewGroupRowInfo gridViewGroupRowInfo = gridViewRowInfo.Group.GroupRow;
                gridViewGroupRowInfo.IsSelected = select;
                if (gridViewGroupRowInfo.GroupLevel != 0)
                {
                    SelectGroup((GridViewRowInfo)gridViewGroupRowInfo.Parent, select);
                }
            }
        }
    }
 
    class MultiSelectGroupedRowInfo : GridViewDataRowInfo
    {
        public static bool ChildSilentUpdate;
 
        public MultiSelectGroupedRowInfo(GridViewInfo viewInfo) : base(viewInfo) { }
 
        protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool value)
        {
            bool result = base.SetBooleanProperty(propertyName, propertyKey, value);
 
            if (propertyName == "IsSelected" && !MultiSelectGroupRowInfo.GroupSilentUpdate)
            {
                ChildSilentUpdate = true;
 
                if (IsSelected)
                {
                    SelectGroupHierachy(true);
                }
                else
                {
                    //check if there are other rows
                    bool selected = GetParentRowSelection(Group.GroupRow);
                    SelectGroupHierachy(selected);
                }
                ChildSilentUpdate = false;
            }
            return result;
        }
 
        private void SelectGroupHierachy(bool select)
        {
            SelectGroup(this, select);
        }
 
        private static void SelectGroup(GridViewRowInfo gridViewRowInfo, bool select)
        {
            if (gridViewRowInfo.Group != null)
            {
                GridViewGroupRowInfo gridViewGroupRowInfo = gridViewRowInfo.Group.GroupRow;
                gridViewGroupRowInfo.IsSelected = select;
                if (gridViewGroupRowInfo.GroupLevel != 0)
                {
                    SelectGroup((GridViewRowInfo) gridViewGroupRowInfo.Parent, select);
                }
            }
        }
 
        private static bool GetParentRowSelection(GridViewGroupRowInfo gridViewGroupRowInfo)
        {
            return gridViewGroupRowInfo.ChildRows.Any(cr => cr.IsSelected);
        }
    }
}
0
Svett
Telerik team
answered on 14 Aug 2012, 11:07 AM
Hello Maarten,

The exception is caused by the wrong cross-recursive implementation of SetBooleanProperty in your rows. You should not use a static field for row instances because they are instantiated more than once. You should use the following variation of your code snippets:
public class MultiSelectGroupedRowInfo : GridViewDataRowInfo
{
    public MultiSelectGroupedRowInfo(GridViewInfo viewInfo) : base(viewInfo) { }
 
    protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool value)
        {
            bool result = base.SetBooleanProperty(propertyName, propertyKey, value);
 
            if (propertyName == "IsSelected")
            {
                GridViewRowInfo rowInfo = this.Parent as GridViewRowInfo;
 
                if (rowInfo != null && rowInfo.Tag == null)
                {
                    bool isSelected = this.IsSelected;
 
                    if (isSelected)
                    {
                        isSelected = rowInfo.ChildRows.All(cr => cr.IsSelected);
                    }
 
                    rowInfo.IsSelected = isSelected;
                }
            }
 
            return result;
        }
}

public class MultiSelectGroupRowInfo : GridViewGroupRowInfo
    {
        public MultiSelectGroupRowInfo(GridViewInfo viewInfo, DataGroup group) : base(viewInfo, group) { }
 
        public override AllowedGridViewRowInfoStates AllowedStates
        {
            get
            {
                return base.AllowedStates | AllowedGridViewRowInfoStates.Selected;
            }
        }
 
        protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool value)
        {
            bool performSelection = propertyName == "IsSelected" && this.Tag == null;
 
            if (performSelection)
            {
                this.Tag = new object();
            }
 
            bool result = base.SetBooleanProperty(propertyName, propertyKey, value);
 
            if (performSelection)
            {
                bool isSelected = this.IsSelected;
 
                foreach (GridViewRowInfo row in this.ChildRows)
                {
                    if (row.Tag == null)
                    {
                        row.IsSelected = isSelected;
                    }
                }
 
                GridViewRowInfo parentRow = this.Parent as GridViewRowInfo;
 
                if (parentRow != null && parentRow.Tag == null)
                {
                    if (isSelected)
                    {
                        isSelected = parentRow.ChildRows.All(cr => cr.IsSelected);
                    }
 
                    parentRow.IsSelected = isSelected;
                }
 
                this.Tag = null;
            }
 
            return result;
        }
    }

I hope this helps.

Greetings,
Svett
the Telerik team
RadControls for WinForms Q2'12 release is now live! Check out what's new or download a free trial >>
Tags
GridView
Asked by
Maarten
Top achievements
Rank 1
Answers by
Svett
Telerik team
Maarten
Top achievements
Rank 1
Share this question
or