我有一个datagridview,左边有3个冻结列,然后我想要的第4列总是显示在右边。其余列显示在第3列和第4列之间,并在其标题中编号(带有1,2,3,4 ......)。我允许用户重新排序这些列,但我希望列标题保持数字顺序。这个想法是用户应该将其视为重新排序列中的数据,而不是列本身。第4列标有" New",如果用户试图将数据放入其中,则会创建一个新列并将数据添加到其中,这也是我希望它总是在右边的原因之一。
为实现此目的,我使用以下ColumnDisplayIndexChanged事件:
private void dgvTreeLevels_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e) {
switch(e.Column.Index) {
case 0:
case 1:
case 2: //prevents columns 0, 1, 2 from being reordered, (freezing just prevents them from being switched with 3+)
SynchronizationContext.Current.Post(delegate(object o) {
if (e.Column.DisplayIndex != e.Column.Index) e.Column.DisplayIndex = e.Column.Index;
}, null);
break;
case 3: //Displays always on the right
SynchronizationContext.Current.Post(delegate(object o) {
if (e.Column.DisplayIndex != dgvTreeLevels.Columns.Count - 1)
e.Column.DisplayIndex = dgvTreeLevels.Columns.Count - 1;
}, null);
break;
default: //Numbered columns
e.Column.HeaderText = (e.Column.DisplayIndex - 2).ToString();
break;
}
}
大部分时间它工作正常。但偶尔行
e.Column.HeaderText = (e.Column.DisplayIndex - 2).ToString();
正在抛出一个ArgumentOutOfRangeException,声明索引超出范围。由于它没有设置任何索引,因此这尤其令人困惑。我无法可靠地创建错误。当我测试功能时,它会偶尔弹出。我认为这可能与尝试将编号列移到最右边有关,但是当我正在做其他事情时,错误会弹出。
检入调试器会显示行中的所有元素都已定义并具有正确的值。我不知道为什么会有错误。堆栈跟踪是
System.ArgumentOutOfRangeException was unhandled
Message="Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: index"
Source="mscorlib"
ParamName="index"
StackTrace:
at System.Collections.ArrayList.get_Item(Int32 index)
at System.Windows.Forms.DataGridViewColumnCollection.get_Item(Int32 index)
at System.Windows.Forms.DataGridView.GetColumnDisplayRectanglePrivate(Int32 columnIndex, Boolean cutOverflow)
at System.Windows.Forms.DataGridView.GetCellDisplayRectangle(Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow)
at System.Windows.Forms.DataGridView.GetCellAdjustedDisplayRectangle(Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow)
at System.Windows.Forms.DataGridView.InvalidateCellPrivate(Int32 columnIndex, Int32 rowIndex)
at System.Windows.Forms.DataGridView.OnColumnHeaderGlobalAutoSize(Int32 columnIndex)
at System.Windows.Forms.DataGridView.OnCellValueChanged(DataGridViewCellEventArgs e)
at System.Windows.Forms.DataGridViewColumnHeaderCell.SetValue(Int32 rowIndex, Object value)
at System.Windows.Forms.DataGridViewColumn.set_HeaderText(String value)
at Customizable_Reports.frmReport.dgvTreeLevels_ColumnDisplayIndexChanged(Object sender, DataGridViewColumnEventArgs e)
at System.Windows.Forms.DataGridView.FlushDisplayIndexChanged(Boolean raiseEvent)
at System.Windows.Forms.DataGridView.CorrectColumnDisplayIndexesAfterDeletion(DataGridViewColumn dataGridViewColumn)
at System.Windows.Forms.DataGridView.OnRemovedColumn_PreNotification(DataGridViewColumn dataGridViewColumn)
at System.Windows.Forms.DataGridViewColumnCollection.RemoveAtInternal(Int32 index, Boolean force)
at System.Windows.Forms.DataGridViewColumnCollection.RemoveAt(Int32 index)
at Customizable_Reports.frmReport.RemoveEmptyColumns()
at Customizable_Reports.frmReport.dgvTreeLevels_CellClick(Object sender, DataGridViewCellEventArgs e)
at System.Windows.Forms.DataGridView.OnMouseClick(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.DataGridView.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at Customizable_Reports.Program.Main()
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
答案 0 :(得分:0)
进一步测试显示,当较高编号的列移动到较低编号的列前面时出现错误,之后被删除。如果由于删除而在ColumnDisplayIndexChanged事件中更新了较低编号列的标题文本,则会发生错误。
您可以通过创建一个新的Winform应用程序来测试它,在表单上放置一个包含两列的datagridview,并允许用户对它们进行重新排序。添加一个按钮和以下两个事件:
private void button1_Click(object sender, EventArgs e) {
dataGridView1.Columns.RemoveAt(1);
}
private void dataGridView1_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e) {
e.Column.HeaderText = e.Column.DisplayIndex.ToString();
}
运行应用程序,拖动第1列前面的第2列,然后按按钮。请注意,必须为列提供唯一标头才能发生此错误。设置e.Column.HeaderText = "test";
代替不会产生错误。
对我而言,这似乎是WinForms中的一个错误,而不是在这个编程中。但我不太清楚会发生什么事情。
将命令传递给当前同步上下文似乎可以解决问题:
SynchronizationContext.Current.Post(delegate(object o) {
e.Column.HeaderText = e.Column.DisplayIndex.ToString();
}, null);