【问题标题】:How do I mimic Windows Explorer multi-select/drag-n-drop behavior in a DataGridView?如何在 DataGridView 中模仿 Windows 资源管理器的多选/拖放行为?
【发布时间】:2010-12-28 21:30:51
【问题描述】:

我试图模仿 Windows 资源管理器处理多项选择的方式。在默认的 DataGridView 中,您可以使用 Ctrl 键单击来选择多个项目。但是,如果您释放 Ctrl 键,然后尝试拖放所选项目,它会清除所选项目并仅选择“命中”行。我在网上某处找到了以下解决方案。

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

但是,这会导致其他副作用。按住 CTRL 键并将鼠标悬停在所选项目上,该项目保持选中状态。这是有道理的,因为如果选择了单击的行,就会绕过 mousedown 事件。从 Windows 资源管理器的行为来看,似乎直到 MouseUp 事件才处理按住 CTRL 键的项目的取消选择。有没有人尝试过这样做?

【问题讨论】:

    标签: c# datagridview multi-select


    【解决方案1】:

    我创建了一个自定义组件来解决这个问题,以及我在 datagridview 中进行多选时遇到的其他一些烦人的问题。这是代码,希望对任何人都有帮助:

    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(e.X, e.Y).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(e.X - (dragSize.Width / 2), e.Y - (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(e.X, e.Y))
            {
                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);
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      这可能对你有帮助:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多