In my previous article, Implementing Copy & Paste between cells in Xceed WPF DataGrid, I outined the method I was using to copy and paste values between cells in the Xceed WPF grid. To recap, this involves using the ApplicationCommands to register to the Copy command and copying the content to the clipboard as text. We then register to the Paste command and when this is received, set the current cell to Edit mode, simulate the text input, and commit the change. The next requirement is to support the selection of a range of cells, and to allow the user to paste a single value to all selected cells. Selection should be in one of three ways - either by dragging the mouse from the first cell to the last, by clicking the cell then clicking the last with shift held down, or by clicking cells with control pressed. As Xceed grid doesn't support multiple cell selection, and I don't want to mess around with the internal workings of Xceed's grid, I decided to create an attached property of type Boolean to attach to each selected cell. The attached property would indicate that that cell is currently selected. However, I then realised that as the Xceed grid is not inheriting from the Selector class, I might as well just reuse the Selector.IsSelected attached property, and avoid having to create my own. So here is the function to select a range of cells and set the attached property on them all. The range to be selected is defined by the "current" cell (which we can get natively from the DataGridControl) and a cell passed to the function.
/// <summary>
/// Selects the range of cell from the "current" cell to the specified cell
/// </summary>
/// <param name="toCell">The cell to select to</param>
private static void SelectRangeFromCurrent(Cell toCell)
{DataGridControl dataGridControl = DataGridControl.GetParentDataGridControl(toCell);
// Need a current item to do anythingif (dataGridControl.CurrentItem == null)
{ return;}
// Find the current cellRow currentRow = (Row) dataGridControl.GetContainerFromItem(dataGridControl.CurrentItem);
Cell currentCell = null;
if (currentRow != null && dataGridControl.CurrentColumn != null)
{currentCell = currentRow.Cells[dataGridControl.CurrentColumn.Index];
}
// Do nothing if it's being editedif (currentCell == null || currentCell.IsBeingEdited)
{ return;}
// Clear the selected status on all the cells ClearSelectedStatus(DataGridControl.GetParentDataGridControl(toCell)); // Get the indexes of the rows and columns we need to loop through int fromRow, toRow, fromColumn, toColumn;GetFromAndToRowAndColumns(dataGridControl, currentCell, toCell, out fromRow, out toRow, out fromColumn, out toColumn);
// Loop and set the IsSelected on all cellsfor (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++)
{Row row = (Row) dataGridControl.GetContainerFromIndex(rowIndex);
for (int columnIndex = fromColumn; columnIndex <= toColumn; columnIndex++)
{Selector.SetIsSelected(row.Cells[columnIndex], true);
}
}
<Style TargetType="xcdg:DataCell">
<Style.Triggers>
<Trigger Property="Selector.IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource LightBlueBrush}" />
</Trigger>
</Style.Triggers>
</Style>
/// <summary>
/// Handles when the mouse goes down over a cell, either deselecting everything, or selecting the single cell (if control is pressed)
/// or selecting the range of cells (if shift is pressed)
/// </summary>
private static void HandleCellMouseDown(object sender, RoutedEventArgs e)
{Cell cell = sender as Cell;
if (cell != null && Mouse.LeftButton == MouseButtonState.Pressed)
{if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{SelectRangeFromCurrent(cell);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{Selector.SetIsSelected(cell, true);
}
else { ClearSelectedStatus(DataGridControl.GetParentDataGridControl(cell));}
}
}
/// <summary>
/// Handles when the mouse enters a cell with the left button depressed, selecting the appropriate range of cells
/// </summary>
private static void HandleCellMouseEnter(object sender, RoutedEventArgs e)
{Xceed.Wpf.DataGrid.Cell cell = sender as Xceed.Wpf.DataGrid.Cell;
if (cell != null && Mouse.LeftButton == MouseButtonState.Pressed)
{SelectRangeFromCurrent(cell);
}
}