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

C# 如何在DataGridView中模拟Windows资源管理器的多选/拖放行为?,c#,datagridview,multi-select,C#,Datagridview,Multi Select,我试图模仿Windows资源管理器处理多个选择的方式。在默认的DataGridView中,可以使用Ctrl单击选择多个项目。但是,如果您释放Ctrl键,然后尝试拖放所选项目,它将清除所选项目,并仅选择“点击”行。我在网上的某个地方找到了以下解决方案 protected override OnMouseDown(MouseEventArgs e) { int hitRowIndex = HitTest(e.X, e.Y).RowIndex; if(!SelectedRows.Contain

我试图模仿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键的项目取消选择。有人试过这样做吗?

这有助于您:

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

我已经创建了一个自定义组件来解决这个问题,以及我在datagridview中使用multi-selection时遇到的一些其他恼人的问题。这是代码,希望它能帮助任何人:

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);
        }
    }
}
公共部分类CustomDataGridView:DataGridView { 公共CustomDataGridView() { 初始化组件(); } 公共CustomDataGridView(IContainer容器) { 容器。添加(此); 初始化组件(); } private bool_delayedMouseDown=false; 私有矩形_dragBoxFromMouseDown=Rectangle.Empty; private Func_getDragData=null; 公共无效启用DragDrop(Func getDragData) { _getDragData=getDragData; } CellMouseDown(DataGridViewCellMouseEventArgs e)上的受保护覆盖无效 { 碱基。OnCellMouseDown(e); 如果(e.RowIndex>=0&&e.Button==MouseButtons.Right) { var currentRow=this.currentRow.Index; var selectedRows=this.selectedRows.OfType().ToList(); var clickedRowSelected=this.Rows[e.RowIndex]。选中; this.CurrentCell=this.Rows[e.RowIndex].Cells[e.ColumnIndex]; //如果控件已关闭或已选择单击的行,请选择以前选择的行 如果((Control.ModifierKeys&Keys.Control)!=0 | |单击下拉选择) selectedRows.ForEach(row=>row.Selected=true); //如果按住shift键,请选择新行范围 如果((Control.ModifierKeys&Keys.Shift)!=0) for(int i=currentRow;i!=e.RowIndex;i+=Math.Sign(e.RowIndex-currentRow)) this.Rows[i].Selected=true; } } MouseEventArgs e上的受保护覆盖无效(MouseEventArgs e) { var rowIndex=base.HitTest(e.X,e.Y).rowIndex; _delayedMouseDown=(行索引>=0&& (SelectedRows.Contains(行[rowIndex])| |(ModifierKeys&Keys.Control)>0); 如果(!\u delayedMouseDown) { base.OnMouseDown(e); 如果(行索引>=0) { //还记得鼠标落下的地方吗。 //DragSize指示鼠标可以移动的大小 //在开始拖动事件之前。 大小dragSize=SystemInformation.dragSize; //使用DragSize创建一个矩形,鼠标位置为 //在矩形的中心。 _dragBoxFromMouseDown=新矩形( 新点(e.X-(dragSize.Width/2),e.Y-(dragSize.Height/2)),dragSize); } 其他的 //如果鼠标不在datagridview中的项目上,请重置矩形。 _dragBoxFromMouseDown=矩形。为空; } } MouseUp上的受保护覆盖无效(MouseEventArgs e) { //在鼠标向上移动之前执行延迟鼠标向下移动 如果(_delayedMouseDown) { _delayedMouseDown=false; base.OnMouseDown(e); } base.OnMouseUp(e); } MouseMove上的受保护覆盖无效(MouseEventArgs e) { 基地移动(e); //如果鼠标移到矩形外,开始拖动。 如果(_getDragData!=null&&(e.Button&MouseButtons.Left)>0&& _dragBoxFromMouseDown!=矩形。空&!\u dragBoxFromMouseDown.Contains(e.X,e.Y)) { 如果(_delayedMouseDown) { _delayedMouseDown=false; 如果((ModifierKeys&Keys.Control)>0) base.OnMouseDown(e); } //继续拖放,传递拖动数据 var dragData=_getDragData(); if(dragData!=null) 这个.DoDragDrop(dragData,DragDropEffects.Move); } } }