3

データグリッドを利用したアプリを開発しています。グリッドの機能のほとんどは、セルのスタイル設定、セル内編集、並べ替えなど、かなり標準的なものになります。ただし、1 つの要件は、Excel などの「ドラッグ アンド フィル」機能を提供することです。ここで、行内の 1 つまたは複数のセルを選択すると、それらの周りに太い境界線が描画されます。境界線の右下隅に小さな四角形があり、これを下にドラッグすると、選択したセルの値が下の行にコピーされます。

これは、.Net WPF データ グリッドを使用して実装しようとするのは恐ろしいことのように思えます (また、この機能を提供する商用データ グリッド コンポーネントもありません)。誰かが同様の機能を開発したか、これを達成するための可能なアプローチを提案しましたか? 従来のコピー & ペーストはオプションではありません。

4

1 に答える 1

1

データグリッドで選択したセルの周りに太い線を引くためのヒントを次に示します。

  • データグリッドの SelectedCellsChanged イベントをサブスクライブします。
  • イベント ハンドラーで、データグリッドの装飾レイヤーを取得し、選択したセルの数が 0 を超えていて、(キャッシュされた) 装飾レイヤーがまだない場合は、それにカスタム 装飾を追加します。装飾のコンストラクターを介してデータグリッドを渡します。選択されたセルの数 == 0 で、キャッシュされた adornerlayer != null の場合、アドナー レイヤーからアドナーを削除します。イベント ハンドラーの最後で、adornerLayer.Update(datagrid) を呼び出します。
  • 次の CustomAdorner クラスを使用します。

    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;
        }
    }
    
于 2015-10-08T14:33:11.853 に答える