问题
We are developing an app that utilises a data grid. Most of the grid's functionality will be fairly standard stuff - styling cells, in-cell editing, sorting, etc. However one requirement is to provide "drag and fill" functionality, like Excel. This is where you select one or more cells inside a row, which then get a thick border drawn around them. The border has a small square on its bottom-right corner, and when you drag this down Excel copies the selected cell values to the rows below.
This sounds like a frightening thing to try and implement using the .Net WPF data grid (and no commercial data grid component provides this feature either). Has anyone developed a similar feature, or suggest possible approaches to accomplishing this? Plain old copy & paste is not an option!
回答1:
Here are some tips to draw a thick line around your selected cells in a datagrid:
- Subscribe to the datagrid's SelectedCellsChanged event.
- In the event handler, get the adorner layer of the datagrid and add a custom adorner to it if the number of selected cells > 0 and if there is no (cached) adornerlayer yet. Pass the datagrid via the adorner's constructor. If the number of selected cells == 0 and the cached adornerlayer != null, remove the adorner from the adorner layer. At the end of the event handler, call adornerLayer.Update(datagrid)
Use the following CustomAdorner class:
public class DataGridSelectionAdorner : Adorner { private readonly DataGrid datagrid; private readonly SolidColorBrush backgroundBrush = new SolidColorBrush(Color.FromArgb(30, 0, 0, 0)); readonly Pen pen = new Pen(new SolidColorBrush(Colors.Black), 1); private readonly Dictionary<DataGridCellInfo, int[]> cellInfoToTableRowAndColumn = new Dictionary<DataGridCellInfo, int[]>(); public DataGridSelectionAdorner(UIElement adornedElement) : base(adornedElement) { datagrid = (DataGrid)adornedElement; pen.DashStyle = new DashStyle(new[] { 3.0, 3.0 }, 0); IsHitTestVisible = false; } protected override void OnRender(DrawingContext drawingContext) { ItemContainerGenerator generator = datagrid.ItemContainerGenerator; IEnumerable<int> rows = datagrid.SelectedCells.Select(c => generator.IndexFromContainer( generator.ContainerFromItem(c.Item) ) ); IEnumerable<int> columns = datagrid.SelectedCells.Select( c => c.Column.DisplayIndex ); int minRow = rows.Min(); int maxRow = rows.Max(); int minColumn = columns.Min(); int maxColumn = columns.Max(); foreach (var cell in datagrid.SelectedCells) { int row = generator.IndexFromContainer(generator.ContainerFromItem(cell.Item)); int column = cell.Column.DisplayIndex; cellInfoToTableRowAndColumn[cell] = new[] { row, column }; } var topLeft = cellInfoToTableRowAndColumn.First(c => c.Value[0] == minRow && c.Value[1] == minColumn).Key; var bottomRight = cellInfoToTableRowAndColumn.First(c => c.Value[0] == maxRow && c.Value[1] == maxColumn).Key; var topLeftCell = GetDataGridCell(topLeft); var bottomRightCell = GetDataGridCell(bottomRight); const double marginX = 4.5; const double marginY = 3.5; Point topLeftPoint = topLeftCell.TranslatePoint(new Point(marginX, marginY), datagrid); Point bottomRightPoint = bottomRightCell.TranslatePoint( new Point(bottomRightCell.RenderSize.Width - marginX, bottomRightCell.RenderSize.Height - marginY), datagrid ); drawingContext.DrawRectangle(backgroundBrush, pen, new Rect(topLeftPoint, bottomRightPoint)); } private static DataGridCell GetDataGridCell(DataGridCellInfo cellInfo) { var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item); if (cellContent != null) return (DataGridCell)cellContent.Parent; return null; } }
来源:https://stackoverflow.com/questions/14258663/implement-drag-and-fill-functionality-in-wpf-datagrid