Hi,
I have a hierarchical grid with custom multi select behavior.
I recently upgraded to Q3 2012. Now I get an exception when I try to select multiple rows that have childrows with the mouse.
This is the exception:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at Telerik.WinControls.UI.GridRowBehavior.DoMultiFullRowSelect(Boolean shift, Boolean control)
at Telerik.WinControls.UI.GridRowBehavior.DoMouseSelection(GridCellElement currentCell, Point currentLocation)
at Telerik.WinControls.UI.GridRowBehavior.ProcessMouseSelection(Point mousePosition, GridCellElement currentCell)
at Telerik.WinControls.UI.GridRowBehavior.OnMouseMove(MouseEventArgs e)
at Telerik.WinControls.UI.BaseGridBehavior.OnMouseMove(MouseEventArgs e)
at Telerik.WinControls.UI.RadGridView.OnMouseMove(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseMove(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at Telerik.WinControls.RadControl.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
----------------------------------------
I made a test application that reproduces the problem.
The application contains 2 files:
I have a hierarchical grid with custom multi select behavior.
I recently upgraded to Q3 2012. Now I get an exception when I try to select multiple rows that have childrows with the mouse.
This is the exception:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at Telerik.WinControls.UI.GridRowBehavior.DoMultiFullRowSelect(Boolean shift, Boolean control)
at Telerik.WinControls.UI.GridRowBehavior.DoMouseSelection(GridCellElement currentCell, Point currentLocation)
at Telerik.WinControls.UI.GridRowBehavior.ProcessMouseSelection(Point mousePosition, GridCellElement currentCell)
at Telerik.WinControls.UI.GridRowBehavior.OnMouseMove(MouseEventArgs e)
at Telerik.WinControls.UI.BaseGridBehavior.OnMouseMove(MouseEventArgs e)
at Telerik.WinControls.UI.RadGridView.OnMouseMove(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseMove(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at Telerik.WinControls.RadControl.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
----------------------------------------
I made a test application that reproduces the problem.
The application contains 2 files:
- Form1.cs
- CustomRowInfos.cs
Form1.cs:
using System;using System.Collections.Generic;using System.Windows.Forms;using Telerik.WinControls.UI;namespace GridWithIndexedHierarchySpike{ public partial class Form1 : Form { public Form1() { InitializeComponent(); dummyGridView.Dock = DockStyle.Fill; dummyGridView.Parent = this; dummyGridView.BringToFront(); dummyGridView.MultiSelect = true; dummyGridView.UseScrollbarsInHierarchy = true; } protected override void OnLoad(EventArgs e) { base.OnLoad(e); GridViewTemplate childTemplate = CreateChildTemplate(); dummyGridView.Templates.Add(childTemplate); childTemplate.HierarchyDataProvider = new GridViewEventDataProvider(childTemplate); //grid events dummyGridView.RowSourceNeeded += gridView_RowSourceNeeded; dummyGridView.CreateRowInfo += CreateGridViewHierarchyRowInfoWithCustomSelectBehavior; dummyGridView.Templates[0].CreateRowInfo += CreateGridViewDataRowInfoWhitCustomSelectBehavior; //databind dummyGridView.DataSource = CreateDummyData(5); } void gridView_RowSourceNeeded(object sender, GridViewRowSourceNeededEventArgs e) { List<SomeData> data = CreateDummyData(2); foreach (SomeData someData in data) { GridViewRowInfo row = e.Template.Rows.NewRow(); row.Cells[0].Value = someData.Name; row.Cells[1].Value = someData.SomeDataId; row.Cells[2].Value = someData.ParentDataId; e.SourceCollection.Add(row); } } private static void CreateGridViewHierarchyRowInfoWithCustomSelectBehavior(object sender, GridViewCreateRowInfoEventArgs e) { if (e.RowInfo is GridViewHierarchyRowInfo) { e.RowInfo = new MultiSelectGridViewHierarchyRowInfo(e.ViewInfo); } } private static void CreateGridViewDataRowInfoWhitCustomSelectBehavior(object sender, GridViewCreateRowInfoEventArgs e) { if (e.RowInfo is GridViewDataRowInfo) { e.RowInfo = new MultiSelectGridViewDataRowInfo(e.ViewInfo); } } private GridViewTemplate CreateChildTemplate() { var template = new GridViewTemplate {AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill}; var namecolumn = new GridViewTextBoxColumn("Name"); var idColumn = new GridViewTextBoxColumn("ID"); var parentColumn = new GridViewTextBoxColumn("Parent"); template.Columns.AddRange(namecolumn, idColumn, parentColumn); return template; } private static List<SomeData> CreateDummyData(int nbrRows) { var data = new List<SomeData>(); var someData = new SomeData { Name = Guid.NewGuid().ToString(), ParentDataId = null, SomeDataId = 0 }; data.Add(someData); for (int i = 1; i <= nbrRows - 1; i++) { var someChildData = new SomeData() { Name = Guid.NewGuid().ToString(), ParentDataId = someData.SomeDataId, SomeDataId = i }; data.Add(someChildData); } return data; } public class SomeData { public int SomeDataId { get; set; } public int? ParentDataId { get; set; } public string Name { get; set; } } }}
CustomRowInfos.cs:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Telerik.WinControls.UI;namespace GridWithIndexedHierarchySpike{ /// <summary> /// Hierarchy row with custom select behavior. /// When the row is (de)selected, all child rows are (de)selected /// </summary> public class MultiSelectGridViewHierarchyRowInfo : GridViewHierarchyRowInfo { public static bool ParentSilentUpdate; public static bool OverrideChildSelection; public MultiSelectGridViewHierarchyRowInfo(GridViewInfo owner) : base(owner) { ParentSilentUpdate = false; } protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool value) { bool result = base.SetBooleanProperty(propertyName, propertyKey, value); if (result && propertyName == "IsSelected") { if (!MultiSelectGridViewDataRowInfo.ChildSilentUpdate) { //parent row is selected/deselected; SelectChildRows(value); } } return result; } private void SelectChildRows(bool isSelected) { if (OverrideChildSelection) return; ParentSilentUpdate = true; foreach (MultiSelectGridViewDataRowInfo row in this.ChildRows) { row.IsSelected = isSelected; } ParentSilentUpdate = false; } } /// <summary> /// Data row with custom select behavior. /// If the row is a child row of a parent row then /// the parent row is selected when the child rows (or one of its siblings) is selected, /// otherwise the parent row is deselected. /// </summary> public class MultiSelectGridViewDataRowInfo : GridViewDataRowInfo { public static bool ChildSilentUpdate; public MultiSelectGridViewDataRowInfo(GridViewInfo viewInfo) : base(viewInfo) { ChildSilentUpdate = false; } public object OriginalBoundItem { get; set; } protected override bool SetBooleanProperty(string propertyName, int propertyKey, bool value) { bool result = base.SetBooleanProperty(propertyName, propertyKey, value); if (result && propertyName == "IsSelected") { if (!MultiSelectGridViewHierarchyRowInfo.ParentSilentUpdate) { //child row is selected SelectParentRow(value); } } return result; } private void SelectParentRow(bool isSelected) { var parent = Parent as MultiSelectGridViewHierarchyRowInfo; if (parent == null) return; ChildSilentUpdate = true; if (isSelected) { parent.IsSelected = true; } else { //check if there are other rows bool selected = GetParentRowSelection(parent); parent.IsSelected = selected; } ChildSilentUpdate = false; } private bool GetParentRowSelection(MultiSelectGridViewHierarchyRowInfo parent) { //if there is one selected child row, return true return parent.ChildRows.Cast<MultiSelectGridViewDataRowInfo>().Any(row => row != this && row.IsSelected); } }}