从另一个线程添加表单上的控件

时间:2010-02-12 09:26:26

标签: c# invoke multithreading

我试图推迟向我的主要表单添加控件,目标是加快它的开始时间。好吧,我遇到以下例外:

  

跨线程操作无效:   控制从线程访问的'Form1'   它创建的线程除外   上。

我试图在一个较小的例子上简单地解决问题,但问题仍然存在。这是我的代码:

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();
        }
    }
}

我确实使用了Invoke方法并检查了InvokeRequiered是否为true,但InvokeRequiered保持“true”。我真的不明白。至少我会期待StackOverflow异常,因为这是一个递归调用。

所以,如果有人遇到类似的问题,请告诉我,我做错了什么?

4 个答案:

答案 0 :(得分:5)

您的代码中的问题是您正在添加两个按钮。

将if块放在else块中。

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);
        }
    }

答案 1 :(得分:1)

您可以这样做......

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);
     });
}

答案 2 :(得分:0)

请改用匿名方法。说明如下。

如果我们有这样的形式:

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();
    }
}

这将抛出异常。

将UpdateText更改为:

private delegate void MyDelegate();

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

或使用匿名方法:

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

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

答案 3 :(得分:0)

使用线程添加按钮非常昂贵!请改用ThreadPool。