How do I simulate the behavior of Multi-select / drag-n-drop in Windows Explorer in a DataGridView?

I am trying to imitate how Windows Explorer handles multiple selections. In the default DataGridView, you can select multiple items using Ctrl-click. But if you release the Ctrl key and then try to drag / drop the selected items, it will clear the selected items and select only the "hit" line. I found the following solution somewhere on the Internet.

protected override OnMouseDown(MouseEventArgs e) { int hitRowIndex = HitTest(eX, eY).RowIndex; if(!SelectedRows.Contains(Rows[hitRowIndex])) { base.OnMouseDown(); } } 

However, this causes other side effects. When the CTRL key is pressed and wiped on the selected item, the item remains selected. This makes sense because the mousedown event is thrown out if a row click is selected. Studying the behavior of Windows Explorer, it seems that deselecting an item with the CTRL key is not processed until the MouseUp event. Has anyone tried to do this?

+3
source share
2 answers

I created a custom component to fix this, and some other annoying problems that I had with multiple choices in datagridview. This is the code, hope it helps someone:

 public partial class CustomDataGridView : DataGridView { public CustomDataGridView() { InitializeComponent(); } public CustomDataGridView(IContainer container) { container.Add(this); InitializeComponent(); } private bool _delayedMouseDown = false; private Rectangle _dragBoxFromMouseDown = Rectangle.Empty; private Func<object> _getDragData = null; public void EnableDragDrop(Func<object> getDragData) { _getDragData = getDragData; } protected override void OnCellMouseDown(DataGridViewCellMouseEventArgs e) { base.OnCellMouseDown(e); if (e.RowIndex >= 0 && e.Button == MouseButtons.Right) { var currentRow = this.CurrentRow.Index; var selectedRows = this.SelectedRows.OfType<DataGridViewRow>().ToList(); var clickedRowSelected = this.Rows[e.RowIndex].Selected; this.CurrentCell = this.Rows[e.RowIndex].Cells[e.ColumnIndex]; // Select previously selected rows, if control is down or the clicked row was already selected if ((Control.ModifierKeys & Keys.Control) != 0 || clickedRowSelected) selectedRows.ForEach(row => row.Selected = true); // Select a range of new rows, if shift key is down if ((Control.ModifierKeys & Keys.Shift) != 0) for (int i = currentRow; i != e.RowIndex; i += Math.Sign(e.RowIndex - currentRow)) this.Rows[i].Selected = true; } } protected override void OnMouseDown(MouseEventArgs e) { var rowIndex = base.HitTest(eX, eY).RowIndex; _delayedMouseDown = (rowIndex >= 0 && (SelectedRows.Contains(Rows[rowIndex]) || (ModifierKeys & Keys.Control) > 0)); if (!_delayedMouseDown) { base.OnMouseDown(e); if (rowIndex >= 0) { // Remember the point where the mouse down occurred. // The DragSize indicates the size that the mouse can move // before a drag event should be started. Size dragSize = SystemInformation.DragSize; // Create a rectangle using the DragSize, with the mouse position being // at the center of the rectangle. _dragBoxFromMouseDown = new Rectangle( new Point(eX - (dragSize.Width / 2), eY - (dragSize.Height / 2)), dragSize); } else // Reset the rectangle if the mouse is not over an item in the datagridview. _dragBoxFromMouseDown = Rectangle.Empty; } } protected override void OnMouseUp(MouseEventArgs e) { // Perform the delayed mouse down before the mouse up if (_delayedMouseDown) { _delayedMouseDown = false; base.OnMouseDown(e); } base.OnMouseUp(e); } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // If the mouse moves outside the rectangle, start the drag. if (_getDragData != null && (e.Button & MouseButtons.Left) > 0 && _dragBoxFromMouseDown != Rectangle.Empty && !_dragBoxFromMouseDown.Contains(eX, eY)) { if (_delayedMouseDown) { _delayedMouseDown = false; if ((ModifierKeys & Keys.Control) > 0) base.OnMouseDown(e); } // Proceed with the drag and drop, passing in the drag data var dragData = _getDragData(); if (dragData != null) this.DoDragDrop(dragData, DragDropEffects.Move); } } } 
+4
source

Maybe this will help you:

  protected override void OnMouseDown(MouseEventArgs e) { int hitRowIndex = HitTest(eX, eY).RowIndex; if ((!SelectedRows.Contains(Rows[hitRowIndex])) || ((ModifierKeys & Keys.Control) != Keys.None)) { base.OnMouseDown(e); } } 
0
source

Source: https://habr.com/ru/post/1484170/


All Articles