Как получить индекс столбца DataGridView в событии MouseUp, а не в событии MouseDown?
У меня есть WinForm с DataGridView
Моя цель состоит в том, чтобы перетащить один столбец и поместить его в другой индекс столбца. Я знаю, что изменение порядка столбцов возможно с помощью AllowUserToOrderColumns = true
, Но я должен выполнить другие операции на DGV. Вот почему мне нужен целевой индекс столбца при событии мыши. Для этого я использую HitTestInfo
:
System.Windows.Forms.DataGrid.HitTestInfo myHitTest;
myHitTest = dataGrid1.HitTest(e.X, e.Y);
int p = myHitTest.ColumnIndex;
Когда я нажимаю на первый столбец DGV, этот код запускается и дает мне индекс столбца (p
). Проблема в том, что когда я опускаю его в другой столбец DGV, я хотел бы знать индекс целевого столбца с тем же кодом p = -1
Я думаю, потому что HitTestInfo
член возвращает значение на MouseDown
а не на MouseUp
, Если кто-нибудь может сказать мне, как это сделать, это было бы очень здорово.
2 ответа
Вы можете создать два объекта HitTestInfo, один в MouseDown
и один в MouseUp
,
ИМО, вы также должны использовать DataGridView.HitTestInfo
класс, а не DataGrid.HitTestInfo
и постарайтесь не называть или имя DataGridViews
DataGrids
, который является аналогичным, но отличается от контроля WPF
!
DataGridView.HitTestInfo myHitTestDown, myHitTestUp;
int visibleColumnDown, visibleColumnUp;
private void dataGrid1_MouseUp(object sender, MouseEventArgs e)
{
myHitTestUp = dataGrid1.HitTest(e.X, e.Y);
visibleColumnUp = getVisibleColumn(dataGrid1, e.X);
}
private void dataGrid1_MouseDown(object sender, MouseEventArgs e)
{
myHitTestDown = dataGrid1.HitTest(e.X, e.Y);
visibleColumnDown = getVisibleColumn(dataGrid1, e.X);
}
Обновление: чтобы найти видимый индекс столбца после того, как столбцы были переупорядочены, просто используйте:
dataGrid1.Columns[myHitTestUp.ColumnIndex].DisplayIndex;
Прежде чем я нашел это, я написал эту маленькую вспомогательную функцию, которая делает то же самое:
int getVisibleColumn(DataGridView dgv, int x)
{
int cx = dgv.RowHeadersWidth;
int c = 0;
foreach (DataGridViewColumn col in dgv.Columns)
{
cx += col.Width; if ( cx >= x) return c; c++;
}
return -1;
}
Узнать, какая колонна была перетасована, немного сложнее. Существует событие, которое вызывается для каждого затронутого столбца, и оно всегда вызывается первым для перетаскиваемого. Вот один из способов сделать это:
Создайте переменные на уровне класса:
List<DataGridViewColumn> shuffled = new List<DataGridViewColumn>();
DataGridViewColumn shuffledColumn = null;
Помните первый столбец:
private void dgvLoadTable_ColumnDisplayIndexChanged(
object sender, DataGridViewColumnEventArgs e)
{
if (shuffledColumn == null) shuffledColumn = e.Column;
}
Забудьте, что случилось раньше:
private void dgvLoadTable_MouseDown(object sender, MouseEventArgs e)
{
shuffledColumn = null;
}
Теперь вы можете использовать его. Выбор столбцов, однако, не очень хорошо тасует их! Если вы делаете
shuffledColumn.Selected = true;
он будет выбран только в том случае, если SelectionMode
либо FullColumnSelect
или же ColumnHeaderSelect
- Боюсь, что в любом режиме тасование не будет работать.
Вы можете использовать drag'n'drop для этого.
Предположим, у вас есть Form
с DataGridView
названный dataGridView1
,
Изначально не забудьте разрешить drag'n'drop для DataGridView
:
dataGridView1.AllowDrop = true;
Обработчик события, который заменяет желаемую функциональность MouseUp
будет dataGridView1_DragDrop
и индекс целевого столбца colIndexOfItemUnderMouseToDrop
:
private Rectangle dragBoxFromMouseDown;
private int colIndexFromMouseDown;
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Proceed with the drag and drop, passing in the list item.
dataGridView1.DoDragDrop(colIndexFromMouseDown, DragDropEffects.Move);
}
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
// Get the index of the item the mouse is below.
colIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).ColumnIndex;
if (colIndexFromMouseDown != -1)
{
// 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 ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void dataGridView1_DragDrop(object sender, DragEventArgs e)
{
// If the drag operation was a move then remove and insert the column.
if (e.Effect == DragDropEffects.Move)
{
// The mouse locations are relative to the screen, so they must be
// converted to client coordinates.
Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));
// Get the column index of the item the mouse is below.
int colIndexOfItemUnderMouseToDrop = dataGridView1.HitTest(clientPoint.X, clientPoint.Y).ColumnIndex;
if (colIndexOfItemUnderMouseToDrop == -1)
return;
colIndexOfItemUnderMouseToDrop = dataGridView1.Columns[colIndexOfItemUnderMouseToDrop].DisplayIndex;
// Now we have the column's display index.
if (e.Data.GetDataPresent(typeof(int)))
{
int colToMove = (int)e.Data.GetData(typeof(int));
dataGridView1.Columns[colToMove].DisplayIndex = colIndexOfItemUnderMouseToDrop;
// Select the column:
dataGridView1.Columns[colToMove].Selected = true;
}
}
}
РЕДАКТИРОВАТЬ
Новый подход:
private DataGridViewColumn columnToMove;
public Form1()
{
InitializeComponent();
dataGridView1.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn { Name = "AAA", SortMode = DataGridViewColumnSortMode.NotSortable },
new DataGridViewTextBoxColumn { Name = "BBB", SortMode = DataGridViewColumnSortMode.NotSortable },
new DataGridViewTextBoxColumn { Name = "CCC", SortMode = DataGridViewColumnSortMode.NotSortable }
});
dataGridView1.Rows.Add(2);
dataGridView1.AllowUserToOrderColumns = true;
dataGridView1.MouseDown += dataGridView1_MouseDown;
dataGridView1.ColumnDisplayIndexChanged += dataGridView1_ColumnDisplayIndexChanged;
}
private void dataGridView1_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
if (e.Column == columnToMove)
{
dataGridView1.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
e.Column.Selected = true;
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
var hti = dataGridView1.HitTest(e.X, e.Y);
if (hti.Type == DataGridViewHitTestType.ColumnHeader)
{
columnToMove = dataGridView1.Columns[hti.ColumnIndex];
dataGridView1.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
}
}