title: datagridview index out of bounds error in event when no index is being set
body: <p>I have a datagridview with 3 frozen columns at the left and then the 4th column I want always displayed on the right. The remaining columns are displayed between columns 3 and 4, and are numbered in their headers (with 1, 2, 3, 4, ...). I allow the users to reorder these columns, but I want the column headers to remain in numeric order. The idea is that the user should see it as reordering the data in the columns, not the columns themselves. Column 4 is labeled "New", and if the user attempts to put data into it, a new column is created and the data is added to it instead, which is part of why I want it always on the right. </p>
  
  <p>To accomplish this, I use the following ColumnDisplayIndexChanged event:</p>
  
  <pre><code>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;
      }
   }
  </code></pre>
  
  <p>Most of the time it works fine. But occasionally the line </p>
  
  <pre><code>              e.Column.HeaderText = (e.Column.DisplayIndex - 2).ToString();
  </code></pre>
  
  <p>is thowing an ArgumentOutOfRangeException stating that the Index is out of range. Since it doesn't set any indexes, this is particularly perplexing. I am not able to reliably create the error. It just pops up on occasions as I am testing the functionality. I think it may be related to attempting to move a numbered column past the right-most, but the error pops up later as I am doing other things.</p>
  
  <p>Checking in the debugger shows that all of the elements in the line are defined and have the correct values. I have no clue why there is an error. The stack trace is</p>
  
  <pre><code>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&amp; m, MouseButtons button, Int32 clicks)
         at System.Windows.Forms.Control.WndProc(Message&amp; m)
         at System.Windows.Forms.DataGridView.WndProc(Message&amp; m)
         at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&amp; m)
         at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
         at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG&amp; 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: 
  </code></pre>