【问题标题】:datagridview index out of bounds error in event when no index is being set未设置索引时,datagridview 索引越界错误
【发布时间】:2016-01-21 21:22:39
【问题描述】:

我有一个数据网格视图,左侧有 3 个冻结列,然后我希望始终显示在右侧的第 4 列。其余列显示在第 3 列和第 4 列之间,并在其标题中编号(带有 1、2、3、4、...)。我允许用户对这些列重新排序,但我希望列标题保持数字顺序。这个想法是用户应该将其视为对列中的数据进行重新排序,而不是列本身。第 4 列标记为“新建”,如果用户尝试将数据放入其中,则会创建一个新列并将数据添加到其中,这也是我希望它始终位于右侧的部分原因。

为此,我使用以下 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: 

【问题讨论】:

    标签: c# events datagridview indexoutofboundsexception


    【解决方案1】:

    进一步的测试表明,当编号较高的列移动到编号较低的列之前,然后又被删除时,就会出现错误。当由于删除而在 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();
      }
    

    运行应用程序,将第 2 列拖到第 1 列前面,然后按下按钮。请注意,必须为列提供唯一的标题才能发生此错误。设置e.Column.HeaderText = "test"; 不会产生错误。

    对我来说,这似乎是 WinForms 中的一个错误,而不是这个编程中的错误。但我对正在发生的事情了解得不够多。

    将命令传递给当前同步上下文似乎可以解决问题:

    SynchronizationContext.Current.Post(delegate(object o) {
         e.Column.HeaderText = e.Column.DisplayIndex.ToString();
    }, null);
    

    【讨论】:

      猜你喜欢
      • 2014-06-06
      • 2015-03-22
      • 2013-10-13
      • 2015-01-10
      • 2014-01-27
      • 2017-03-23
      • 2020-04-23
      相关资源
      最近更新 更多