Add a control on a form, from another Thread
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 f开发者_C百科ollowing 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?
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);
}
}
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);
});
}
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";
}
It's very expensive to use a thread for just adding a button ! Use the ThreadPool instead.
精彩评论