locked
IndexOutOfRangeException on DataGridView RRS feed

  • Question

  • Hello,

     

    I've come across a problem that's been driving me nuts for the past couple days.  I'll explain first what this part of the form is being used for.  Have two datagridviews that is giving me status information about another piece of software I'm monitoring.  The first dgv is used just to report an Online / Offline status.  The Second is used to give me vital stats about all the machines running that software (IPAddress, CPU Usage, Memory available, Memory used, Total Memory,....).  I have a class that polls for that status every 5 seconds.  Once it's finished polling, I call my form and pass a dataset containing two datatables.  At that point I'm setting the datasource of my two dgv's to the datatables within that dataset.  The problem I'm running into is a completly random error.  I can't find a single common denominator that could explain why this is happening.   The error message is below, followed by my code.  Has anyone else run into this problem?  I've some some similar things, but the suggestions so far have not helped.

     

    System.IndexOutOfRangeException: Index 0 does not have a value.
       at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
       at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 rowIndex)

     

    (sorry it's pretty ugly when I copy/paste code in here...it removed all my tabs..)

    Code Snippet

    public void RefreshStatus(DataSet Status) {

    try {

    UpdateMachineStatus(Status.Tables["MachineStatus"]);

    UpdateMainStatus(Status.Tables["MainStatus"]);

    }

    catch (Exception ex) {

    Program.log.Add("Error updating datagridview status.", ex);

    }

    }

    private void UpdateMachineStatus(DataTable StatusData) {

    if (this.dgvMachineStatus.InvokeRequired) {

    SetDataTableCallBack d = new SetDataTableCallBack(UpdateMachineStatus);

    this.Invoke(d, new object[] { StatusData });

    }

    else {

    try {

    if (StatusData.Rows.Count > 0) {

    this.dgvMachineStatus.DataSource = StatusData;

    this.dgvMachineStatus.Refresh();

    }

    }

    catch (Exception ex) {

    Program.log.Add("Error updaing Machine Status", ex);

    }

    }

    }

    private void UpdateMainStatus(DataTable StatusData) {

    if (this.dgvMainStatus.InvokeRequired) {

    SetDataTableCallBack d = new SetDataTableCallBack(UpdateMainStatus);

    this.Invoke(d, new object[] { StatusData });

    }

    else {

    try {

    if (StatusData.Rows.Count > 0) {

    this.dgvMainStatus.DataSource = StatusData;

    this.dgvMainStatus.Refresh();

    foreach (DataGridViewRow dr in dgvMainStatus.Rows) {

    if (dr.Cells.Count > 0) {

    if (dr.Cells[0].Value.ToString().Contains("Off")) {

    dgvMainStatus.Rows[dr.Index].Cells[0].Style.BackColor = Color.Red;

    dgvMainStatus.Rows[dr.Index].Cells[0].Style.SelectionBackColor = Color.Red;

    }

    else {

    dgvMainStatus.Rows[dr.Index].Cells[0].Style.BackColor = Color.Green;

    dgvMainStatus.Rows[dr.Index].Cells[0].Style.SelectionBackColor = Color.Green;

    }

    }

    }

    }

    }

    catch (Exception ex) {

    Program.log.Add("Error updating Main Status", ex);

    }

    }

    }

     

     

    private void SetDataGridViewErrorHandler() {

    dgvFactoryStatus.DataError += new DataGridViewDataErrorEventHandler(dgv_DataError);

    dgvMachineStatus.DataError += new DataGridViewDataErrorEventHandler(dgv_DataError);

    dgvMainStatus.DataError += new DataGridViewDataErrorEventHandler(dgv_DataError);

    }

     

     

    void dgv_DataError(object sender, DataGridViewDataErrorEventArgs e) {

    Program.log.Add("Error updating Datagridview. Context:" + e.Context.ToString(), e.Exception);

    ErrorCount = ErrorCount + 1;

    lblErrors.Text = "Form Errors: " + ErrorCount;

    }

     

     

    Also another thing I find is the errors seem to happen more frequently when I'm clicking around on my datagridview.  I'm not sure if that has anything to do with the problem or not.

     

    Thanks,

    Cory

     

    Monday, June 18, 2007 4:11 PM

All replies

  • Something is confused.  The Currency Manager is supposed to maintain the current values of the records.  The index 0 is not valid.  Is it possible that your callback is causing a loop of updates?

    Monday, June 18, 2007 8:40 PM
  • I don't believe so, I can physically see my datagridview refresh every 5 seconds.  I made a couple changes that seem to help, but I still recieve this error randomly when I click on the control.  If it just idle's and recieves the refresh, I don't get any errors.

     

    Below is one of my updated methods, but it still gets errors randomly with mouse clicks.  I also included my main status class that retrives the status and passes it back to my form.

     

    Code Snippet

    private void UpdateMainStatus(DataTable StatusData) {

    if (this.dgvMainStatus.InvokeRequired) {

    SetDataTableCallBack d = new SetDataTableCallBack(UpdateMainStatus);

    this.Invoke(d, new object[] { StatusData });

    }

    else {

    try {

    this.dgvMainStatus.DataSource = StatusData;

    this.dgvMainStatus.Refresh();

    foreach (DataGridViewRow dr in dgvMainStatus.Rows) {

    foreach (DataGridViewCell dc in dr.Cells) {

    if (dc.Value.ToString().Contains("Off")) {

    dgvMainStatus.Rows[dr.Index].DefaultCellStyle.BackColor = Color.Red;

    dgvMainStatus.Rows[dr.Index].DefaultCellStyle.SelectionBackColor = Color.Red;

    }

    else {

    dgvMainStatus.Rows[dr.Index].DefaultCellStyle.BackColor = Color.Green;

    dgvMainStatus.Rows[dr.Index].DefaultCellStyle.SelectionBackColor = Color.Green;

    }

    }

    }

    }

    catch (Exception ex) {

    Program.log.Add("Error updating Main Status", ex);

    }

    }

    }

     

    Here is my class that generates the status and calls my form with updates.

    Code Snippet

    public class V2Status {

    private DateTime LastEmailTimeStamp;

    private Timer StatusTimer;

    private int ErrorCounter;

    private DataTable MainTempStatus;

    private DataTable MachineTempStatus;

    private DataTable GenericTempStatus;

    private DataSet Status;

    private DataTable MainStatus;

    private DataTable MachineStatus;

    private DataTable GenericStatus;

    public V2Status() {

    ErrorCounter = 0;

    InitializeTables();

    }

    public void Start() {

    Execute();

    StatusTimer = new Timer();

    StatusTimer.Interval = 5000;

    StatusTimer.AutoReset = true;

    StatusTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);

    StatusTimer.Start();

    }

    public void Stop() {

    StatusTimer.Stop();

    StatusTimer.Dispose();

    }

    private void TimerElapsed(object sender, ElapsedEventArgs e) {

    lock (this) {

    Execute();

    }

    }

    private void Execute() {

    try {

    if (Program.config.V2Status) {

    if (Status == null) {

    this.Status = new DataSet();

    }

    else {

    Status.Reset();

    }

    RefreshStatus();

    CheckDataManager();

    Status.Tables.Add(this.MainStatus);

    Status.Tables.Add(this.MachineStatus);

     

    Program.V2ops.RefreshStatus(this.Status);

    }

    }

    catch (Exception ex) {

    Program.log.Add("Error refreshing V2 Status", ex);

    }

    }

    private void CheckDataManager() {

    try {

    GenericStatus Status = Job_CORBA_Link.ORB.DataStatus();

    this.MainTempStatus.Rows.Add("Datamanager Online");

    }

    catch (Exception ex) {

    Program.log.Add("Error refreshing datamanager status.", ex);

    this.MainTempStatus.Rows.Add("Datamanager Offline");

    }

    finally {

    this.MainStatus.Clear();

    this.MainStatus = MainTempStatus.Copy();

    this.MainTempStatus.Dispose();

    }

    }

     

    public void RefreshStatus() {

    try {

    this.MachineTempStatus = MachineStatus.Clone();

    this.MainTempStatus = MainStatus.Clone();

     

    ProcessStatus Status = Job_CORBA_Link.ORB.V2Status();

    FactoryStatus[] FactoryStatusList = Status.mFactoryStatusList;

     

    MachineStatus mStatus = new MachineStatus();

    mStatus.CreateStructure(FactoryStatusList);

     

    foreach (MachinePanelData m in mStatus.MachineData) {

    this.AddMachineStatusRow(m.mIPAddress, m.mFactoryCount, m.mEngineCount, m.mMemReserve, m.mMemFree, m.mTotalMemory, m.mCPU);

    }

    ErrorCounter = 0;

    this.MainTempStatus.Rows.Add("Supervisor Online");

    }

    catch (Exception ex) {

    Program.log.Add("Error Refreshing Status.", ex);

    this.MainTempStatus.Rows.Add("Supervisor Offline");

    if ((ErrorCounter == 5) && (LastEmailTimeStamp.TimeOfDay <= (DateTime.Now.TimeOfDay - new TimeSpan(1, 0, 0)))) {

    ErrorCounter = 0;

    LastEmailTimeStamp = DateTime.Now;

    Email e = new Email();

    e.SendEMail(Program.config.Email_SMTPHost, Program.config.Email_V2OpsErrorEmailFrom,

    Program.config.Email_V2OpsErrorReplyTo, "CRITICAL ERROR",

    @"Error communicating with V2. Is the supervisor running?" +

    Environment.NewLine +

    "Error Message Reported: " + ex.Message,

    true, e.SplitString(Program.config.Email_V2OpsErrorTo));

    }

    if (ErrorCounter > 5) {

    ErrorCounter = 0;

    }

    else {

    ErrorCounter = ErrorCounter + 1;

    }

    }

    finally {

    this.MachineStatus.Clear();

    this.MachineStatus = MachineTempStatus.Copy();

    this.MachineTempStatus.Dispose();

    }

    }

     

    private void AddMachineStatusRow(string IPAddress, int FactoryCount, int EngineCount, int MemReserve, int MemFree, int TotalMemory, int CPU) {

    MachineTempStatus.Rows.Add(IPAddress, FactoryCount, EngineCount, MemReserve, MemFree, TotalMemory, CPU);

    }

     

    private void InitializeTables() {

    MainStatus = new DataTable("MainStatus");

    MainStatus.Columns.Add("Status");

     

    MachineStatus = new DataTable("MachineStatus");

    MachineStatus.Columns.Add("IPAddress");

    MachineStatus.Columns.Add("Factories");

    MachineStatus.Columns.Add("Engines");

    MachineStatus.Columns.Add("Memory Reserved");

    MachineStatus.Columns.Add("Memory Free");

    MachineStatus.Columns.Add("Total Memory");

    MachineStatus.Columns.Add("CPU Usage");

    }

    }

     

    Monday, June 18, 2007 9:04 PM
  • I think you need to you preventing your refresh code being called by the button event handler when it is already executing the on behalf of the timer expiration handler. 

     

    jerry

     

    Monday, June 18, 2007 11:50 PM
  • I don't have any button events on this form, the only event handler that actually updates this form is my timer.  As a test, I ran my application overnight, no errors occurred.  This morning, as soon as I started clicking on the form (moving it, selecting a cell, or just randomly clicking all over the form), I started recieving errors.  I can't make sence of it, has anyone else experienced this?  Is there any suggestions I can try to figure out exactly why this is happening?

     

    Thanks!

    Cory

    Tuesday, June 19, 2007 1:32 PM
  • Cory,
    I am getting the same exception, its also driving me nuts. I have a datagridview bound to a bindingsource with a filter set. I have managed to narrow my error down to my rowvalidating event handler. for some reason if i add a row to the end of the datagridview (when bound to filtered data) i get this exception. You can cath it in you dataerror handler and discard to stop users seeing it but im not sure if it has any adverse effects and i would like to get to the bottom of it.

    One other thing is that when adding a row to the end of my filtered datagridview the validation handler fires once and no exception occurs. I then fires a second time and thats when i get this exception. I cant really see many similarities between what you are doing and what I am doing other than the fact that we both try and access the current row in one of our handlers. This seems pretty random to me, perhaps this error is hiding some deeper problem but i havent got to the bottom of it yet.

    Any ideas anyone?

    Imran
    Friday, August 3, 2007 8:41 AM
  • I also encountered this problem with no apparent reason. Using the debugger I am able to find out the cause. At the time time of base.Dispose, the DataGridView has some items while its DataSource (a BindingSource) has 0. The call stack is in DataGridView.OnDraw, so I walkaround the problem by hiding the control and clearing the rows.

    It seems the number of item is not changed even after I called the ResetBindings method of the BindingSource.
    Wednesday, January 9, 2008 10:21 PM
  • I also had this problem.  I solved it by making sure of calling dataGridView.Dispose() and bindingSourceDispose() when appropriate, in my case in the Form.Closed_Event.
    • Proposed as answer by amro nabil Thursday, October 8, 2009 7:40 AM
    Tuesday, February 3, 2009 4:44 PM
  • I'm not sure but if you binding dgv to  a view from database and you don't have method to call update you have to set propertie for dgv (allow user to add rows and delete rows and editing to false) this may help
    Thursday, October 8, 2009 7:46 AM
  • Hello eric.T,

    Thanks for this solution. It worked great in my program, and took two minutes after I found your post. Good Work!!!

    George Elam

    Houston, TX

    Friday, April 27, 2012 1:36 AM
  • Thank Eric. T so much.

    --The Anh--

    Tuesday, September 23, 2014 3:25 PM
  • I solved the same problem with Application.DoEvents() at the start of my Refresh code.
    Monday, October 1, 2018 12:29 AM