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);
}
}
}