7

I was trying to postpone adding controls to my main form, with a goal to speed up it's start time. Well I run in the following exception:

Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.

I tried to simply the problem on a smaller example but the problem stays. Here is my code:

using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace AddConrolFromAnotherThread {
    public partial class Form1 : Form {

        public Form1() {
            InitializeComponent();
        }


        private void AddButton() { 
            if(this.InvokeRequired){
                this.Invoke(new MethodInvoker(this.AddButton));
            }
            Random random = new Random(2);
            Thread.Sleep(20);
            Button button = new Button();
            button.Size = new Size(50,50);
            button.Location = 
                new Point(random.Next(this.Width),random.Next(this.Height));
                this.Controls.Add(button);
        }

        private void buttonStart_Click(object sender, EventArgs e) {
            Thread addControlThread = 
                new Thread(new ThreadStart(this.AddButton));
            addControlThread.Start();
        }
    }
}

I did use the Invoke method and did check if InvokeRequiered is true, but InvokeRequiered keep staying "true". I really don't understand that. At least I would expect StackOverflow exception, since this is a recursion call.

So, if anyone met the similar problem, please could you tell me what did I do wrong?

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
Gico
  • 1,276
  • 2
  • 15
  • 30

4 Answers4

6

The problem in your code is that your are adding two buttons.

Put the code after the if block in an else block.

private void AddButton() { 
        if(this.InvokeRequired){
            this.Invoke(new MethodInvoker(this.AddButton));
        }
        else {
           Random random = new Random(2);
           Thread.Sleep(20);
           Button button = new Button();
           button.Size = new Size(50,50);
           button.Location = new Point(random.Next(this.Width),random.Next(this.Height));
           this.Controls.Add(button);
        }
    }
Jehof
  • 34,674
  • 10
  • 123
  • 155
1

You can do this like....

private void AddButton() { 
    if(this.InvokeRequired) {
        Invoke((MethodInvoker)delegate ()
        {
            Random random = new Random(2);
            Thread.Sleep(20);
            Button button = new Button();
            button.Size = new Size(50,50);
            button.Location = new 
            Point(random.Next(this.Width),random.Next(this.Height));
            this.Controls.Add(button);
     });
}
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
0

Use anonymous methods instead. Explanation is below.

If we have form like this:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Thread t = new Thread(new ThreadStart(Start));
        t.Start();
    }

    private void UpdateText()
    {
        button1.Text = "New Text";
    }

    void Start()
    {
        UpdateText();
    }
}

This will throw an exception.

Change UpdateText to:

private delegate void MyDelegate();

private void UpdateText()
{
    if (button1.InvokeRequired)
    {
       button1.Invoke(new MyDelegate(UpdateText));
    }
    button1.Text = "New Text";
}

or use anonymous method:

void Start() 
{
    this.Invoke((MyDelegate)delegate
    {
        UpdateText();
    });
}

private void UpdateText()
{
    button1.Text = "New Text";
}
sashaeve
  • 9,387
  • 10
  • 48
  • 61
  • Hi, Sash. Thank you for a quick answer. But I am not sure if we understand each other. I did check if form requires the Invoke call. And in my case I do not update a control, I am just trying to add a new one on the form. – Gico Feb 12 '10 at 09:42
  • The difference is not so big - you have to create control you want to add in the same thread as Form (after InitializeComponent for example) and than just add it from the separate thread using approaches I described. – sashaeve Feb 12 '10 at 10:05
0

It's very expensive to use a thread for just adding a button ! Use the ThreadPool instead.

Islam Yahiatene
  • 1,441
  • 14
  • 27