我如何模仿一个DataGridView Windows资源管理器多选/拖欧米茄下降的行为? [英] How do I mimic Windows Explorer multi-select/drag-n-drop behavior in a DataGridView?

查看:117
本文介绍了我如何模仿一个DataGridView Windows资源管理器多选/拖欧米茄下降的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图模仿Windows资源管理器处理多项选择的方式。在默认的DataGridView,可以使用Ctrl键单击选择多个项目。但是,如果你松开Ctrl键,然后尝试和拖/放所选的项目,它清除选定的项目,只选择了打行。我发现下面的解决方案网上的某个地方。

I'm trying to mimic the way Windows Explorer handles multiple selection. In a default DataGridView, you can select multiple items using Ctrl-click. But if you release the Ctrl key and then try and drag/drop the selected items, it clears the selected items and only selects the "hit" row. I found the following solution somewhere online.

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



然而,这会导致其他副作用。随着CTRL键按下,鼠标悬停倒在选定​​的项目,该项目保持选中状态。这是有意义的,因为如果该行点击选择鼠标按下事件被旁路。通过观察Windows资源管理器的行为,它看起来像一个项目时,首先保持,直到MouseUp事件不处理的CTRL键解除选择。有没有人试图做到这一点?

However, this causes other side effects. With the CTRL key pressed and mousing down on a selected item, the item remains selected. This makes sense because the mousedown event is bypassed if the row clicked on is selected. From looking at the behavior of Windows Explorer, it looks like the deselection of an item with the CTRL key held is not handled until the MouseUp event. Has anyone tried to do this?

推荐答案

我创建了一个自定义组件来解决这个问题,以及其他一些恼人的问题,我曾与多选在datagridview的。这是代码,希望它可以帮助任何人:

I have created a custom component to fix this, and some other annoying issues I had with multi selection in datagridview. This is the code, hope it helps anyone:

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);
        }
    }
}

这篇关于我如何模仿一个DataGridView Windows资源管理器多选/拖欧米茄下降的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆