将Winforms对话框直接放置在DataGridView单元格上



我有一个DataGridView与2列的文件名。我想在这些文件名上模拟Windows文件资源管理器的"重命名"上下文菜单。为此,我创建了一个简单的WinForms对话框,没有标题,只有一个用于重命名的文本框条目。我在右键单击网格的文件名单元格时显示它。我试图将其直接定位在单元格上,但一直无法让它显示在正确的位置。它向下移了几行,向右移了几个字符宽度。我这样定位对话框:

Point location;
void dataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e) {
var cellRect = dataGridView.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
// Point location = dataGridView.Location;
location = dataGridView.Bounds.Location;
location.Offset(cellRect.Location);
location = dataGridView.PointToScreen(location);
}
async void renameToolStripMenuItem_Click(object sender, EventArgs e) {
using (var rfd = new RenameFileDialog(fi)) {
// Lifted from designer
rfd.ControlBox = false;
rfd.Text = string.Empty;
rfd.formBorderStyle = FormBorderStyle.SizableToolWindow;
// Actually in method
rfd.StartPosition = FormStartPosition.Manual;
rfd.Location = location;
rfd.ShowDialog(dataGridView);
}
}

我怀疑我被绊倒了位置vs ClientRectangle vs控制边界或边距或填充,但我还没能确定不希望的偏移来自哪里。有人能告诉我如何定位对话框,或者建议一种方法来模拟资源管理器的"重命名'在一个dataGridView?

原罪在这里:

location = dataGridView.Bounds.Location;

将控件的原点转换为屏幕坐标,使用控件本身作为相对参考,必须考虑其自身的原点,这始终是(0, 0)(Point.Empty)。
如果你使用它的Location属性,你会考虑控件相对于它的父控件的偏移量。
如果使用此度量并调用Control.PointToScreen(),则检索控件的客户端区域内的位置
在其ClientRectangle内的位置的偏移量,添加到此度量中,然后当然向右和向下移动(因为控件的原点不在(0, 0))

也就是说,控件原点的屏幕坐标是:

[Control].PointToScreen(Point.Empty);

正如在DataGridView下打开表单中所描述的,您只需要考虑引发CellMouseDown事件的单元格的边界:

Point location = Point.Empty;
private void dataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
var dgv = sender as DataGridView;
var cellRect = dgv.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
location = dgv.RectangleToScreen(cellRect).Location;
}

值得注意的是,在正常情况下,GetCellDisplayRectangle()返回的坐标相对于Cell的网格向右移动了7个像素,向下移动了1个像素,因为它考虑了内部边界
如果您想将表单定位在Cell的网格上,您可以添加:

location.Offset(-7, -1);

最新更新