Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual Studio Crashes! - Collection was modified after the enumerator was instantiated

Hey i have a UserControl that kept crashing my Visual Studio. So i ran another instance of VS and debugged the other VS and this is what i figured:

Collection was modified after the enumerator was instantiated.

Here is my array:

    private static Color[] colors = 
    {
        Color.FromArgb(155, 188, 255), //    40000
        Color.FromArgb(156, 189, 255), //    39500
        Color.FromArgb(157, 188, 255), //    39000
        Color.FromArgb(156, 189, 254), //    38500
    };

And here is my loop that crashes the bussines

    public Heater()
    {
        InitializeComponent();
        this.tarTemp = this.curTemp;
        new Thread(() => UpdateTemp(true)).Start(); 
    }

    private delegate void UpdateTempDelegate(bool loop);
    private void UpdateTemp(bool loop)
    {
        if (lblTemp.InvokeRequired)
        {
            UpdateTempDelegate del = new UpdateTempDelegate(UpdateTemp);
            lblTemp.Invoke(del, loop);
        }
        else
        {
            do
            {
                lblTemp.Text = curTemp + C;
                if (curTemp >= 0)
                {
                    int i = curTemp - 10;
                    if (i < 0)
                        i = 0;
                    if (i > colors.Length - 1)
                        i = colors.Length - 1;
                    this.BackColor = colors[i]; // I'M CRASHING !!!
                }
            } while (loop && !this.Disposing);
        }
    }

The line that crashes the Visual Studio Designer is this.BackColor = colors[i];

Here is the image of the running Threads:

Threads

All threads stopped on the same line... this.BackColor = colors[i];

Here is the EventViewer crash log:

Application: devenv.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException
Stack:
   at System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource)
   at System.Collections.Generic.SortedList`2+SortedListValueEnumerator[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].MoveNext()
   at Microsoft.VisualStudio.Shell.ServiceProviderHierarchy.GetService(System.Type)
   at System.ComponentModel.Design.ServiceContainer.GetService(System.Type)
   at System.ComponentModel.Design.DesignerHost.GetService(System.Type)
   at System.ComponentModel.Design.DesignerHost+Site.System.IServiceProvider.GetService(System.Type)
   at System.Windows.Forms.Control.get_AmbientPropertiesService()
   at System.Windows.Forms.Control.get_BackColor()
   at System.Windows.Forms.Control.set_BackColor(System.Drawing.Color)
   at Multiplier.Heater.UpdateTemp(Boolean)
   at Multiplier.Heater.<.ctor>b__0()
   at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

This is the weirdest thing i encountered so far. Help whould be appriciated.

like image 353
Danpe Avatar asked Oct 25 '22 01:10

Danpe


1 Answers

As you found out, your code is crashing the designer, taking VS down with it. The problem is that you start a thread in design mode, triggered by the designer running some of your code at design time. It for example will run the constructor, the Load event, OnHandleCreated, etcetera. That makes for a very nice design-time experience, your control will look just like it does at runtime.

But that can also cause plenty of problems. You have to avoid running code that may cause an exception when it runs in a different execution context. Classic examples are trying to open a file without specifying the full path, opening a dbase connection with the dbase server offline or unreachable. And definitely starting a thread, InvokeRequired is not going to reliably work as the designer constructs and destroys the native window handle. The fix is simple:

public Heater()
{
    InitializeComponent();
    this.tarTemp = this.curTemp;
    if (!this.DesignMode) {
        new Thread(() => UpdateTemp(true)).Start(); 
    }
}

You'll need to do more work, this code won't work well at runtime either. The threaded code will bomb when the form on which the user control is placed is closed. Once you fix that, odds are good that it now works correctly at design-time as well. But don't.

like image 178
Hans Passant Avatar answered Nov 15 '22 05:11

Hans Passant