To reproduce:
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'nwindDataSet.Products' table. You can move, or remove it, as needed.
this.productsTableAdapter.Fill(this.nwindDataSet.Products);
// TODO: This line of code loads data into the 'nwindDataSet.Order_Details' table. You can move, or remove it, as needed.
this.order_DetailsTableAdapter.Fill(this.nwindDataSet.Order_Details);
// TODO: This line of code loads data into the 'nwindDataSet.Categories' table. You can move, or remove it, as needed.
this.categoriesTableAdapter.Fill(this.nwindDataSet.Categories);
radGridView1.DataSource = nwindDataSet.Categories;
GridViewTemplate firstChildtemplate = new GridViewTemplate();
firstChildtemplate.DataSource = nwindDataSet.Products;
firstChildtemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
radGridView1.MasterTemplate.Templates.Add(firstChildtemplate);
GridViewRelation relation = new GridViewRelation(radGridView1.MasterTemplate);
relation.ChildTemplate = firstChildtemplate;
relation.RelationName = "CategoriesProducts";
relation.ParentColumnNames.Add("CategoryID");
relation.ChildColumnNames.Add("CategoryID");
radGridView1.Relations.Add(relation);
GridViewTemplate secondChildtemplate = new GridViewTemplate();
secondChildtemplate.DataSource = nwindDataSet.Order_Details;
secondChildtemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
firstChildtemplate.Templates.Add(secondChildtemplate);
GridViewRelation relation2 = new GridViewRelation(firstChildtemplate);
relation2.ChildTemplate = secondChildtemplate;
relation2.RelationName = "ProductsOrderDetails";
relation2.ParentColumnNames.Add("ProductID");
relation2.ChildColumnNames.Add("ProductID");
radGridView1.Relations.Add(relation2);
this.radGridView1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill;
this.radGridView1.MultiSelect = true;
this.radGridView1.SelectionMode = Telerik.WinControls.UI.GridViewSelectionMode.CellSelect ;
}
Please refer to the attached gif file illustrating the error when performing multiple selection.
1. Workaround: use Shift + arrow keys to perform multiple selection.
2. Workaround: custom row behavior:
BaseGridBehavior behavior = (BaseGridBehavior)this.radGridView1.GridBehavior;
behavior.UnregisterBehavior(typeof(GridViewHierarchyRowInfo));
behavior.RegisterBehavior(typeof(GridViewHierarchyRowInfo), new MyGridRowBehavior());
public class MyGridRowBehavior : GridHierarchyRowBehavior
{
protected override bool ProcessMouseSelection(Point mousePosition, GridCellElement currentCell)
{
if (this.RootGridBehavior.LockedBehavior != this)
{
this.GridControl.Capture = true;
this.RootGridBehavior.LockBehavior(this);
}
bool result = this.DoMouseSelection(currentCell, mousePosition);
return result;
}
private bool DoMouseSelection(GridCellElement currentCell, Point currentLocation)
{
if (!this.MasterTemplate.MultiSelect || this.GridViewElement.Template.AllowRowReorder)
{
return false;
}
Point mouseDownLocation = (Point)typeof(GridRowBehavior).GetField("mouseDownLocation", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
Rectangle rect = new Rectangle(mouseDownLocation.X - SystemInformation.DragSize.Width / 2, mouseDownLocation.Y - SystemInformation.DragSize.Height / 2,
SystemInformation.DragSize.Width, SystemInformation.DragSize.Height);
if (rect.Contains(currentLocation))
{
return false;
}
GridTableElement tableElement = this.GridViewElement.CurrentView as GridTableElement;
if (tableElement == null)
{
return false;
}
bool selectionStartedOnAPinnedColumn = (bool)typeof(GridRowBehavior).GetField("selectionStartedOnAPinnedColumn", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
bool mouseDownOnLeftPinnedColumn = (bool)typeof(GridRowBehavior).GetField("mouseDownOnLeftPinnedColumn", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
bool mouseDownOnRightPinnedColumn = (bool)typeof(GridRowBehavior).GetField("mouseDownOnRightPinnedColumn", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
bool selectionStartedOnAPinnedRow = (bool)typeof(GridRowBehavior).GetField("selectionStartedOnAPinnedRow", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
bool mouseDownOnTopPinnedRow = (bool)typeof(GridRowBehavior).GetField("mouseDownOnTopPinnedRow", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
bool mouseDownOnBottomPinnedRow = (bool)typeof(GridRowBehavior).GetField("mouseDownOnBottomPinnedRow", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
if (selectionStartedOnAPinnedColumn && this.GetViewportBounds(tableElement).Contains(currentLocation))
{
if (mouseDownOnLeftPinnedColumn)
{
tableElement.HScrollBar.Value = tableElement.HScrollBar.Minimum;
mouseDownOnLeftPinnedColumn = false;
}
if (mouseDownOnRightPinnedColumn)
{
tableElement.HScrollBar.Value = tableElement.HScrollBar.Maximum - tableElement.HScrollBar.LargeChange + 1;
mouseDownOnRightPinnedColumn = false;
}
selectionStartedOnAPinnedColumn = false;
}
if (selectionStartedOnAPinnedRow && this.GetViewportBounds(tableElement).Contains(currentLocation))
{
if (mouseDownOnTopPinnedRow)
{
tableElement.VScrollBar.Value = tableElement.VScrollBar.Minimum;
mouseDownOnTopPinnedRow = false;
}
if (mouseDownOnBottomPinnedRow)
{
tableElement.VScrollBar.Value = tableElement.VScrollBar.Maximum - tableElement.VScrollBar.LargeChange + 1;
mouseDownOnBottomPinnedRow = false;
}
selectionStartedOnAPinnedRow = false;
}
if (currentCell.RowInfo is GridViewDataRowInfo)
{
if (this.MasterTemplate.SelectionMode == GridViewSelectionMode.FullRowSelect)
{
typeof(GridHierarchyRowBehavior).GetMethod("DoMultiFullRowSelect", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, new object[] { currentCell, currentLocation });
}
else
{
this.DoMultiCellSelect(currentCell, currentLocation);
}
}
return true;
}
private GridRowElement GetFirstScrollableRowElement(GridTableElement tableElement)
{
if (tableElement.ViewElement.ScrollableRows.Children.Count < 1)
{
return null;
}
return (GridRowElement)tableElement.ViewElement.ScrollableRows.Children[0];
}
private GridViewColumn GetFirstScrollableColumn(GridTableElement tableElement)
{
GridRowElement rowElement = this.GetFirstScrollableRowElement(tableElement);
if (rowElement == null)
{
return null;
}
int counter = 0;
while (counter < rowElement.VisualCells.Count)
{
if (!rowElement.VisualCells[counter].IsPinned && rowElement.VisualCells[counter].ColumnInfo is GridViewDataColumn)
{
return rowElement.VisualCells[counter].ColumnInfo;
}
counter++;
}
return null;
}
private int GetRowIndex(GridViewRowInfo rowInfo)
{
List<GridViewRowInfo> orderedRows = typeof(GridRowBehavior).GetField("orderedRows", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as List<GridViewRowInfo>;
return orderedRows.IndexOf(rowInfo);
}
private void DoMultiCellSelect(GridCellElement currentCell, Point currentLocation)
{
#region GridViewSelection
int rowUnderMouseIndex = this.GetRowIndex(this.RootGridBehavior.RowAtPoint.RowInfo);
int columnUnderMouseIndex = 0;
GridTableElement tableElement = this.GridViewElement.CurrentView as GridTableElement;
GridViewColumn col = this.RootGridBehavior.CellAtPoint.ColumnInfo;
if (this.RootGridBehavior.CellAtPoint.ColumnInfo is GridViewRowHeaderColumn)
{
col = this.GetFirstScrollableColumn(tableElement);
}
List<GridViewRowInfo> orderedRows = typeof(GridRowBehavior).GetField("orderedRows", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as List<GridViewRowInfo>;
List<GridViewColumn> orderedColumns = typeof(GridRowBehavior).GetField("orderedColumns", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as List<GridViewColumn>;
if (col != null)
{
columnUnderMouseIndex = orderedColumns.IndexOf(col);
}
List<GridViewRowInfo> rows = new List<GridViewRowInfo>();
int anchorRowIndex = (int)typeof(GridRowBehavior).GetField("anchorRowIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
int startIndex = Math.Min(anchorRowIndex, rowUnderMouseIndex);
int endIndex = Math.Max(anchorRowIndex, rowUnderMouseIndex);
for (int i = startIndex; i < endIndex; i++)
{
if (i < 0)
{
continue;
}
if (this.GridViewElement.Template.ChildRows.Count > i)
{
rows.Add(orderedRows[i]);
}
}
int anchorColumnIndex = (int)typeof(GridRowBehavior).GetField("anchorColumnIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
int columnLeft = Math.Min(anchorColumnIndex, columnUnderMouseIndex);
int columnRight = Math.Max(anchorColumnIndex, columnUnderMouseIndex);
GridViewSelectionCancelEventArgs cancelArgs = new GridViewSelectionCancelEventArgs(rows, columnLeft, columnRight);
this.MasterTemplate.EventDispatcher.RaiseEvent<GridViewSelectionCancelEventArgs>(EventDispatcher.SelectionChanging, this, cancelArgs);
if (cancelArgs.Cancel)
{
return;
}
#endregion
bool isProcessedShiftOrControl = this.IsPressedShift || this.IsPressedControl;
ObservableCollection<GridViewCellInfo> SelectedCells = typeof(GridViewSelectedCellsCollection).GetProperty("ObservableItems",
BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this.MasterTemplate.SelectedCells) as ObservableCollection<GridViewCellInfo>;
SelectedCells.BeginUpdate();
this.GridViewElement.CurrentView.BeginUpdate();
int count = this.MasterTemplate.SelectedCells.Count;
bool notifyUpdates = this.ProcessCellSelection(rowUnderMouseIndex, columnUnderMouseIndex);
if (isProcessedShiftOrControl)
{
notifyUpdates = count != this.MasterTemplate.SelectedCells.Count;
}
this.GridViewElement.CurrentView.EndUpdate(false);
SelectedCells.EndUpdate(notifyUpdates);
}
private bool ProcessCellSelection(int rowUnderMouseIndex, int columnUnderMouseIndex)
{
int currentRowIndex = (int)typeof(GridRowBehavior).GetField("currentRowIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
int anchorRowIndex = (int)typeof(GridRowBehavior).GetField("anchorRowIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
int currentColumnIndex = (int)typeof(GridRowBehavior).GetField("currentColumnIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
int anchorColumnIndex = (int)typeof(GridRowBehavior).GetField("anchorColumnIndex", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
if ((rowUnderMouseIndex == currentRowIndex && columnUnderMouseIndex == currentColumnIndex) || (rowUnderMouseIndex < 0 || columnUnderMouseIndex < 0))
{
return false;
}
bool verticalDirectionChange = (rowUnderMouseIndex < currentRowIndex && currentRowIndex > anchorRowIndex && rowUnderMouseIndex < anchorRowIndex) ||
(rowUnderMouseIndex > currentRowIndex && currentRowIndex < anchorRowIndex && rowUnderMouseIndex > anchorRowIndex);
bool horizontalDirectionChange = (columnUnderMouseIndex < currentColumnIndex && currentColumnIndex > anchorColumnIndex && columnUnderMouseIndex < anchorColumnIndex) ||
(columnUnderMouseIndex > currentColumnIndex && currentColumnIndex < anchorColumnIndex && columnUnderMouseIndex > anchorColumnIndex);
List<GridViewRowInfo> orderedRows = typeof(GridRowBehavior).GetField("orderedRows", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as List<GridViewRowInfo>;
List<GridViewColumn> orderedColumns = typeof(GridRowBehavior).GetField("orderedColumns", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this) as List<GridViewColumn>;
if (verticalDirectionChange || horizontalDirectionChange)
{
int rowStartIndex = Math.Min(anchorRowIndex, currentRowIndex);
int rowEndIndex = Math.Max(anchorRowIndex, currentRowIndex);
int colStartIndex = Math.Min(anchorColumnIndex, currentColumnIndex);
int colEndIndex = Math.Max(anchorColumnIndex, currentColumnIndex);
for (int i = rowStartIndex; i <= rowEndIndex; i++)
{
for (int j = colStartIndex; j <= colEndIndex; j++)
{
GridViewCellInfo cell = orderedRows[i].Cells[orderedColumns[j].Index];
if (cell != null && cell.IsSelected)
{
cell.IsSelected = false;
}
}
}
}
bool expandingSelectionUp = rowUnderMouseIndex < currentRowIndex && rowUnderMouseIndex < anchorRowIndex;
bool expandingSelectionDown = rowUnderMouseIndex > currentRowIndex && rowUnderMouseIndex > anchorRowIndex;
bool expandingSelectionLeft = columnUnderMouseIndex < currentColumnIndex && columnUnderMouseIndex < anchorColumnIndex;
bool expandingSelectionRight = columnUnderMouseIndex > currentColumnIndex && columnUnderMouseIndex > anchorColumnIndex;
if (expandingSelectionDown || expandingSelectionUp || expandingSelectionLeft || expandingSelectionRight)
{
int rowStartIndex = Math.Min(anchorRowIndex, rowUnderMouseIndex);
int rowEndIndex = Math.Max(anchorRowIndex, rowUnderMouseIndex);
int colStartIndex = Math.Min(anchorColumnIndex, columnUnderMouseIndex);
int colEndIndex = Math.Max(anchorColumnIndex, columnUnderMouseIndex);
for (int i = rowStartIndex; i <= rowEndIndex; i++)
{
for (int j = colStartIndex; j <= colEndIndex; j++)
{
GridViewCellInfo cell = orderedRows[i].Cells[orderedColumns[j].Index];
if (cell != null && !cell.IsSelected)
{
cell.IsSelected = true;
}
}
}
}
else
{
bool shrinkingSelectionUp = rowUnderMouseIndex < currentRowIndex && rowUnderMouseIndex >= anchorRowIndex;
bool shrinkingSelectionDown = rowUnderMouseIndex > currentRowIndex && rowUnderMouseIndex <= anchorRowIndex;
bool shrinkingSelectionLeft = columnUnderMouseIndex < currentColumnIndex && columnUnderMouseIndex >= anchorColumnIndex;
bool shrinkingSelectionRight = columnUnderMouseIndex > currentColumnIndex && columnUnderMouseIndex <= anchorColumnIndex;
if (shrinkingSelectionUp || shrinkingSelectionDown)
{
int rowStartIndex = Math.Min(currentRowIndex, rowUnderMouseIndex);
int rowEndIndex = Math.Max(currentRowIndex, rowUnderMouseIndex);
int colStartIndex = Math.Min(anchorColumnIndex, columnUnderMouseIndex);
int colEndIndex = Math.Max(anchorColumnIndex, columnUnderMouseIndex);
if (shrinkingSelectionUp)
{
rowStartIndex += 1;
}
if (shrinkingSelectionDown)
{
rowEndIndex -= 1;
}
for (int i = rowStartIndex; i <= rowEndIndex; i++)
{
if (i != anchorRowIndex)
{
for (int j = colStartIndex; j <= colEndIndex; j++)
{
GridViewCellInfo cell = orderedRows[i].Cells[orderedColumns[j].Index];
if (cell != null && cell.IsSelected)
{
cell.IsSelected = false;
}
}
}
}
}
if (shrinkingSelectionLeft || shrinkingSelectionRight)
{
int rowStartIndex = Math.Min(anchorRowIndex, rowUnderMouseIndex);
int rowEndIndex = Math.Max(anchorRowIndex, rowUnderMouseIndex);
int colStartIndex = Math.Min(currentColumnIndex, columnUnderMouseIndex);
int colEndIndex = Math.Max(currentColumnIndex, columnUnderMouseIndex);
if (shrinkingSelectionLeft)
{
colStartIndex += 1;
}
if (shrinkingSelectionRight)
{
colEndIndex -= 1;
}
for (int i = rowStartIndex; i <= rowEndIndex; i++)
{
for (int j = colStartIndex; j <= colEndIndex; j++)
{
if (j != anchorColumnIndex)
{
GridViewCellInfo cell = orderedRows[i].Cells[orderedColumns[j].Index];
if (cell != null && cell.IsSelected)
{
cell.IsSelected = false;
}
}
}
}
}
}
typeof(GridRowBehavior).GetField("currentRowIndex", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(this, rowUnderMouseIndex);
typeof(GridRowBehavior).GetField("currentColumnIndex", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(this, columnUnderMouseIndex);
return true;
}
private Rectangle GetViewportBounds(GridTableElement tableElement)
{
ScrollableRowsContainerElement scrollableRows = tableElement.ViewElement.ScrollableRows;
Rectangle bounds = tableElement.ViewElement.ScrollableRows.ControlBoundingRectangle;
for (int index = 0; index < scrollableRows.Children.Count; index++)
{
GridVirtualizedRowElement virtualizedRow = scrollableRows.Children[index] as GridVirtualizedRowElement;
if (virtualizedRow != null)
{
VirtualizedColumnContainer scrollableColumns = virtualizedRow.ScrollableColumns;
bounds.X = this.GridViewElement.RightToLeft ? virtualizedRow.RightPinnedColumns.ControlBoundingRectangle.Right
: virtualizedRow.LeftPinnedColumns.ControlBoundingRectangle.Right;
bounds.Width = scrollableColumns.ControlBoundingRectangle.Width;
break;
}
}
return bounds;
}
}