Home > Software design >  I get "Collection was modified; enumeration operation may not execute" exception, when I r
I get "Collection was modified; enumeration operation may not execute" exception, when I r

Time:01-08

I have following code for drawing a chart, from data that is read from a csv file. The data is generated from a C# windows service and added to the file every 35ms. In my code I am reading the file every second and updating my chart with the new accumulated data from the file. That means every time I read the file, I read more data then the last time. So I am generating something like a live chart that is updating every second.

When I read the data once, when all the data is generated, from the file, then my chart is working fine. But when I read every second the collected data from the file and throw it to my list, then I get immediatly the exception "Collection was modified; enumeration operation may not execute".

In all the entries about this problem, it is suggested to add a .ToList() to the for each operation. I have done this, but still getting the problem.

public Form1()
    {
        InitializeComponent();
        this.Load  = Form1_Load;
    }
    System.Timers.Timer timer_Chart_update = new System.Timers.Timer();
    
    private void Form1_Load(object sender, EventArgs e)
    {
        this.Controls.Add(chart2);
        Init_Chart_Update_Timer();
    }    

    public static List<double> List_Position = new List<double>();
    public static List<double> List_Current = new List<double>();
    public static List<double> List_X_Axis = new List<double>();

    public void Init_Chart_Update_Timer()
    {
        timer_Chart_update.Elapsed  = new ElapsedEventHandler(OnTimedEvent);
        timer_Chart_update.Interval = 1000;
        timer_Chart_update.Start();
    }

    private void OnTimedEvent(object sender, EventArgs e)
    {
        Read_Test_File();
        Draw_Chart();
    }
    public void Read_Test_File()
    {
        List_Position.Clear();
        try
        {

            using (var fs = new FileStream("D:\\ConCheetah\\Test4\\test_files\\test_01.csv", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))              

            using (var streamReader = new StreamReader(fs, Encoding.UTF8, true))
            {
                String line;
                while ((line = streamReader.ReadLine()) != null)
                {
                    if (line == "$")
                    {
                        break;
                    }
                    bool isLetter = !String.IsNullOrEmpty(line) && Char.IsLetter(line[0]);
                    if (isLetter == true)
                    {
                        continue;
                    }
                    List_Position.Add(double.Parse(line));
                }
            }
        }

        catch(Exception e)
        {
            using (var writer = new StreamWriter(@"D:\ConCheetah\test4\log6.txt", true))
            {
                writer.WriteLine("File Read Error "   e  " "  DateTime.Now.ToString());
            }
        }
        
    }

    public void Draw_Chart()
    {
        
        chart2.Series.Clear();
        chart2.Titles.Clear();
        chart2.Legends.Clear();
        var newSeries_1 = new Series();
        var newSeries_2 = new Series();
        newSeries_1.ChartType = SeriesChartType.Line;
        newSeries_2.ChartType = SeriesChartType.Line;
        chart2.Series.Add(newSeries_1);
        chart2.Series.Add(newSeries_2);
        List_X_Axis.Clear();

        for (int w = 0; w <= 940; w  )
        {
            List_X_Axis.Add(w);
        }

        var t = chart2.Titles.Add("Title1");
        t.Text =  "  Position/Current";
        t.ForeColor = Color.Silver;
        chart2.ChartAreas[0].AxisX.Title = ".";
        chart2.ChartAreas[0].AxisY.Title = "mm";
        chart2.ChartAreas[0].AxisY.TitleForeColor = Color.Orange;
        chart2.ChartAreas[0].AxisY.LabelStyle.ForeColor = Color.Orange;
        chart2.ChartAreas[0].AxisX.Minimum = 0d;
        chart2.Series[0].Color = Color.Orange;
        chart2.ChartAreas[0].AxisY.Minimum = 0;
        chart2.ChartAreas[0].AxisY.Maximum = 15;
        chart2.ChartAreas[0].AxisY2.Enabled = AxisEnabled.True;
        chart2.ChartAreas[0].AxisY2.Minimum = -350;
        chart2.ChartAreas[0].AxisY2.Maximum = 350;
        chart2.ChartAreas[0].AxisY2.Title = "% of Max. Current";
        chart2.ChartAreas[0].AxisY2.TitleForeColor = Color.Yellow;
        chart2.ChartAreas[0].AxisY2.LabelStyle.ForeColor = Color.Yellow;
        chart2.ChartAreas[0].AxisY2.MajorGrid.LineColor = Color.Silver;
        chart2.ChartAreas[0].AxisY2.MajorTickMark.LineColor = Color.Silver;
        chart2.Series[1].YAxisType = AxisType.Secondary;
        chart2.Series[1].Color = Color.Yellow;

        chart2.ChartAreas[0].BackColor = Color.Black;

        int x = 1;
        foreach (float v in List_Position.ToList())
        {
            newSeries_1.Points.AddXY(x, v);
            x  ;
        }
        int x2 = 1;
        foreach (float v in List_Position.ToList())
        {
            newSeries_2.Points.AddXY(x2, v);
            x2  ;
        }

    }

Update_1

System.InvalidOperationException: Collection was modified; enumeration operation may not execute. at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.List1.Enumerator.MoveNextRare() at System.Collections.Generic.List1.Enumerator.MoveNext() at System.Windows.Forms.DataVisualization.Charting.Series.ResetAutoValues(Boolean reset) at System.Windows.Forms.DataVisualization.Charting.Series.UnPrepareData(ISite controlSite) at System.Windows.Forms.DataVisualization.Charting.Data.DataManager.ChartPicture_AfterPaint(Object sender, ChartPaintEventArgs e) at System.Windows.Forms.DataVisualization.Charting.ChartPicture.OnAfterPaint(ChartPaintEventArgs e)

CodePudding user response:

As Ralf has explained in the comment above the problem was that I used the chart control in the timer thread. So my timer was not synchronised with my form (main thread) and I got this error. I updated my timer initialisation as following, and it worked.

 public void Init_Chart_Update_Timer()
    {
        timer_Chart_update.SynchronizingObject = this;
        timer_Chart_update.Elapsed  = new ElapsedEventHandler(OnTimedEvent);
        timer_Chart_update.Interval = 1000;
        timer_Chart_update.Start();

    }
  • Related