如何在 DataGridView 中模仿 Windows 资源管理器的多选/拖放行为?

发布于 2024-08-16 09:57:36 字数 505 浏览 0 评论 0原文

我正在尝试模仿 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 资源管理器的行为来看,按住 CTRL 键取消选择项目似乎直到 MouseUp 事件才得到处理。有人尝试这样做吗?

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ぺ禁宫浮华殁 2024-08-23 09:57:36

我创建了一个自定义组件来解决这个问题,以及我在 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);
        }
    }
}

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);
        }
    }
}
瑕疵 2024-08-23 09:57:36

可能这对您有帮助:

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

May be this help you:

    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);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文