我的表单中包含DataGridView
,我想将列AutoSizeMode
设置为Fill
,将网格ColumnHeadersHeightSizeMode
设置为AutoSize
。我的问题是,如果鼠标光标在表单加载时意外地悬停在网格的左上角单元格,则应用程序将抛出InvalidOperationException
。
这是我在表单加载时应该看到的内容: (注意光标是如何悬停在左上角的单元格上的。)
此代码会引发异常:
static class Program
{
[STAThread]
static void Main()
{
// Make sure the mouse will hover upper left cell when the form loads:
var form = new MyForm { StartPosition = FormStartPosition.Manual };
form.SetDesktopLocation(Cursor.Position.X - 30, Cursor.Position.Y - 40);
Application.Run(form);
}
class MyForm : Form
{
public MyForm()
{
var grid = new DataGridView { Dock = DockStyle.Fill };
grid.Columns.Add("ColumnName", "HeaderText");
// The form will load if I remove one of the two next lines:
grid.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
grid.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
Controls.Add(grid);
}
}
}
在我的配置中,Visual Studio吞下了异常,因此我必须从Windows资源管理器或命令提示符运行该应用程序才能看到错误。
这是堆栈跟踪:
System.InvalidOperationException: This operation cannot be performed while an auto-filled column is being resized.
at System.Windows.Forms.DataGridView.PerformLayoutPrivate(Boolean useRowShortcut, Boolean computeVisibleRows, Boolean invalidInAdjustFillingColumns, Boolean repositionEditingControl)
at System.Windows.Forms.DataGridView.SetColumnHeadersHeightInternal(Int32 columnHeadersHeight, Boolean invalidInAdjustFillingColumns)
at System.Windows.Forms.DataGridView.AutoResizeColumnHeadersHeight(Boolean fixedRowHeadersWidth, Boolean fixedColumnsWidth)
at System.Windows.Forms.DataGridView.OnColumnHeadersGlobalAutoSize()
at System.Windows.Forms.DataGridView.set_TopLeftHeaderCell(DataGridViewHeaderCell value)
at System.Windows.Forms.DataGridView.get_TopLeftHeaderCell()
at System.Windows.Forms.DataGridView.GetCellInternal(Int32 columnIndex, Int32 rowIndex)
at System.Windows.Forms.DataGridView.OnCellMouseEnter(DataGridViewCellEventArgs e)
at System.Windows.Forms.DataGridView.UpdateMouseEnteredCell(HitTestInfo hti, MouseEventArgs e)
at System.Windows.Forms.DataGridView.OnColumnWidthChanged(DataGridViewColumnEventArgs e)
at System.Windows.Forms.DataGridView.OnBandThicknessChanged(DataGridViewBand dataGridViewBand)
at System.Windows.Forms.DataGridViewBand.set_ThicknessInternal(Int32 value)
at System.Windows.Forms.DataGridView.AdjustFillingColumns()
at System.Windows.Forms.DataGridView.ComputeLayout()
at System.Windows.Forms.DataGridView.PerformLayoutPrivate(Boolean useRowShortcut, Boolean computeVisibleRows, Boolean invalidInAdjustFillingColumns, Boolean repositionEditingControl)
at System.Windows.Forms.DataGridView.OnHandleCreated(EventArgs e)
at System.Windows.Forms.Control.WmCreate(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.DataGridView.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
两个问题针对同一问题:Here和here,但在应用建议的答案时应用程序仍然崩溃。
我是否在提供的示例中打破了某种最佳做法? 有没有人之前遇到过这种行为并知道解决方法?
答案 0 :(得分:7)
这似乎是一个错误 - 代码试图访问dataGridView.TopLeftHeaderCell
,当第一次发生时实际创建该单元格并触发一些当时不期望的布局操作。
考虑到所有这些,修复很简单。我们需要确保在TopLeftHeaderCell
处理之前创建DataGridView
,方法是添加以下行(例如,在将网格添加到Controls
之前)
var topLeftHeaderCell = grid.TopLeftHeaderCell; // Make sure TopLeftHeaderCell is created
答案 1 :(得分:3)
非常感谢Ulf提供的优秀样本,展示了如何重现这一点。我的一位客户向我报告了这个错误,你的样本非常宝贵。
将Ivan的优秀答案更进一步,从DataGridView
继承创建自己的网格应该永久地防止这个荒谬的错误。确保在整个应用程序中始终使用自定义网格。
public class Grid
: DataGridView
{
protected override void OnHandleCreated(EventArgs e)
{
// Touching the TopLeftHeaderCell here prevents
// System.InvalidOperationException:
// This operation cannot be performed while
// an auto-filled column is being resized.
var topLeftHeaderCell = TopLeftHeaderCell;
base.OnHandleCreated(e);
}
}
答案 2 :(得分:0)
你的问题与主线程绘制界面的事实有关。
实际上你在启动应用程序运行之前和布局操作(控件)都在挂起布局块内完全初始化之前处理绘图(起始位置)。
更改方法可以解决问题(无需更改代码,只需添加一些内容)。
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
public class MyForm : Form
{
public MyForm()
{
this.InitializeComponents();
}
private void MyForm_Shown(object sender, EventArgs e)
{
this.SetDesktopLocation(Cursor.Position.X - 30, Cursor.Position.Y - 40);
}
private void InitializeComponents()
{
this.SuspendLayout();
this.StartPosition = FormStartPosition.Manual ;
var grid = new DataGridView { Dock = DockStyle.Fill };
grid.Columns.Add("ColumnName", "HeaderText");
// The form will load if I remove one of the two next lines:
grid.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
grid.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
Controls.Add(grid);
this.Shown += new System.EventHandler(this.MyForm_Shown);
this.ResumeLayout(false);
}
}
}
答案 3 :(得分:0)
在.net core(3.1.9)和.net5.0中,这是不可复制的。没有直接修复,但是以某种方式也没有例外。请参阅(并发布,如果您仍然遇到此问题):https://github.com/dotnet/winforms/issues/1830。