[英]How do I mimic Windows Explorer multi-select/drag-n-drop behavior in a DataGridView?
我試圖模仿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鍵的項目的取消選擇。 有沒有人試過這樣做?
我已經創建了一個自定義組件來解決這個問題,以及我在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);
}
}
}
可能對此有所幫助:
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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.