Dusty
Dusty

Reputation: 423

Cross Threading Controls

I'm currently trying to create a timer that will run a chunk of code every few milliseconds. the problem is i want to be able to Modify the position of a picture box that is created on the same thread as the timer, I end up getting the Invoke object error even though its not created on the original thread ?

private void frmMain_Load(object sender, EventArgs e)
{
    //Update Timer Thread
    UpdateThread = new Thread(new ThreadStart(UpdateWindow));
    SleepTime = (int)1000/MaxFps;
    UpdateThread.Start();        
    //.....
}

delegate void SetTextCB(string text);
delegate void SetControl(Control cntrl);

public void TimerThread()
{
    //Controls
    PictureBox TestPicBox;

    //Test TestPicBox
    TestPicBox = new PictureBox();
    TestPicBox.Image = Image.FromFile(TestImage.bmp");
    TestPicBox.Top = 20;
    TestPicBox.Left = 20;
    TestPicBox.Width = 64;
    TestPicBox.Height = 64;
    FilePanelControl(TestPicBox);

    while (true)
    {
        //--Sleep
        Thread.Sleep(SleepTime);
        //--FPS
        if (DateTime.Now.ToString("HH:mm:ss") != SystemTime)
        {
            if (blnShowFps) { lblFpsTextsSet(UpdateFps.ToString() + "-FPS"); }
            else { lblFpsTextsSet(""); }
            SystemTime = DateTime.Now.ToString("HH:mm:ss");
            UpdateFps = 0;
        }
        UpdateFps++;
        //Sleep Time
        SleepTime = (int)1000 / MaxFps;

        //Do UpDate Logic
        TestPicBox.location = new point(10,10);
    }
}

//--Add Control
private void FilePanelControl(Control added)
{
    if (this.FilePanel.InvokeRequired)
    {
        SetControl d = new SetControl(FilePanelControl);
        this.Invoke(d, new object[] { added });
    }
    else
    {
        this.FilePanel.Controls.Add(added);
    }
}

//--lblFps.text
private void lblFpsTextsSet(string text)
{
    if (this.lblFPS.InvokeRequired)
    {
        SetTextCB d = new SetTextCB(lblFpsTextsSet);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.lblFPS.Text = text;
    }
}

hoping i don't have to invoke every control i declare on this thread as the plan was to make a picture box list, so the user could add picture boxes as needed.

Thanks For the help.

Upvotes: 3

Views: 1315

Answers (2)

Dmitry Shkuropatsky
Dmitry Shkuropatsky

Reputation: 3965

The same InvokeRequired and Invoke (or BeginInvoke) should be used to set PictureBox.Location. Control properties must be set on the thread where the control handle was created, that is decided by WinForms, not where the control itself was created.

The reasons are explained in Control.InvokeRequired.

Here is more information on multithreading in Windows Forms Controls that includes an example of using a background thread.

Upvotes: 1

SLaks
SLaks

Reputation: 887767

You should use a System.Windows.Forms.Timer instead of creating your own thread.

This way, everthying will already be on the UI thread.

Upvotes: 3

Related Questions