0

I have a class file that sends an integer to my Form2 class which then a function within this class uses the integer to update my picturebox1 image-location and Form2 size.

The integer is a ID of the current map I am in (in a irrelevant game).

Here are the 2 scenarios that play out.

1) Now, if my Form2 is opened prior to the function being executed (due to not in-game yet due to no id) and then the function is executed (due to now being in-game) , I get a System.InvalidOperationException @ the line 'this.Refresh();'.

2) Now, if I leave Form2 unopened, enter the game and then open Form2, the picturebox1 image is now loaded; however, the form size is not updated. If I then hide Form2 and enter a new map (new ID), I get a System.InvalidOperationException @ the line 'this.Size...'. Also, if I do not hide the form in the aforementioned sentence and then enter a new map, I get the same error as in scenario 1.

Code

The following is my Form2 class file that has the functions which are related to the two errors above.

public partial class Form2 : Form
{
    #region Imports

    [DllImport("kernel32.dll")]
    static extern void OutputDebugString(string lpOutputString);

    #endregion

    #region Variables

    public delegate void UpdateControlsDelegate();

    public static Form2 _Form2;

    #endregion

    public Form2()
    {
        InitializeComponent();

        _Form2 = this;
    }

    Map map = new Map();
    public void MUpdate(int m)
    {
        OutputDebugString("{MUpdate} map= " + m.ToString());

        if (m <= 90000)
        {
            pictureBox1.ImageLocation = "http://randomspam.co/MAP/0000" + m.ToString() + ".img/miniMap.canvas.png";
        }
        else
        {
            if (m <= 900000)
            {
                pictureBox1.ImageLocation = "http://randomspam.co/MAP/000" + m.ToString() + ".img/miniMap.canvas.png";
            }
            else
            {
                if (m <= 9000000)
                {
                    pictureBox1.ImageLocation = "http://randomspam.co/MAP/00" + m.ToString() + ".img/miniMap.canvas.png";
                }
                else
                {
                    pictureBox1.ImageLocation = "http://randomspam.co/MAP/" + m.ToString() + ".img/miniMap.canvas.png";
                }
            }
        }

        FUpdate();

        try
        {
            toolTip1.SetToolTip(pictureBox1, map[m]);
        }
        catch
        { 

        }
    }

    public void InvokeUpdateControls()
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new UpdateControlsDelegate(FUpdate));
        }
        else
        {
            FUpdate();
        }
    }

    private void FUpdate()
    {
        this.Size = new Size(pictureBox1.Width + 6, pictureBox1.Height + 24);

        this.Refresh();
    }
}

Errors

Here are the errors that will be related to the 2 scenarios above.

1)

  System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Cross-thread operation not valid: Control 'form2' accessed from a thread other than the thread it was created on.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.get_Handle()
       at System.Windows.Forms.Control.Invalidate(Boolean invalidateChildren)
       at System.Windows.Forms.Control.Refresh()
       at sorprendente.Form2.FUpdate() in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Form2.cs:line 93
       at sorprendente.Form2.MUpdate(Int32 m) in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Form2.cs:line 65
       at sorprendente.FInteraction.FMTransfer(Int32 m) in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Pipes.cs:line 272
       at sorprendente.PInteraction.ReadPipe() in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Pipes.cs:line 204
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

2)

  System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Cross-thread operation not valid: Control 'form2' accessed from a thread other than the thread it was created on.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.get_Handle()
       at System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Form.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Control.SetBounds(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
       at System.Windows.Forms.Control.set_Size(Size value)
       at System.Windows.Forms.Form.set_Size(Size value)
       at sorprendente.Form2.FUpdate() in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Form2.cs:line 91
       at sorprendente.Form2.MUpdate(Int32 m) in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Form2.cs:line 65
       at sorprendente.FInteraction.FMTransfer(Int32 m) in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Pipes.cs:line 272
       at sorprendente.PInteraction.ReadPipe() in C:\Users\Andrew\Documents\Visual Studio 2010\Projects\MSC\sorprendente\Pipes.cs:line 204
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

I clearly do not understand how to bypass these errors, so any information regarding on how to fix my current problem will be appreciated.

If you request to see any additional class files/functions that may be related to the error, I am more than willing to post them.

Riot
  • 15,723
  • 4
  • 60
  • 67
Andrew
  • 552
  • 2
  • 10
  • 29
  • You need `this.invoke` for `MUpdate()` function too. – Karthik Kalyanasundaram Mar 10 '14 at 02:19
  • Why do you have a static reference to your form in the first place? I bet you the `FInteraction` class is the blame, using that reference to invoke the update method... – Jeff Mercado Mar 10 '14 at 02:29
  • Others reading this thread in the future, looking for help with a similar problem would be better served, if you had left the question as it was originally posted – Mick Mar 10 '14 at 03:45

1 Answers1

1

Use the debug location toolbar in visual studio to check which thread you're on.

This other class of yours is spawning a new thread, MUpdate is not executed on the Windows thread. As already explained in the comments above, you cannot perform operations on windows controls on any thread other than the main windows thread. This includes properties such as pictureBox1.ImageLocation and Size.

To update controls from a thread other than the windows thread you must do that via Invoke, as demonstrated in your own code InvokeUpdateControls which you are not actually calling.

Mick
  • 6,527
  • 4
  • 52
  • 67