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

Posted

技术标签:

【中文标题】从另一个线程在表单上添加控件【英文标题】:Add a control on a form, from another Thread 【发布时间】:2011-01-16 02:00:28 【问题描述】:

我试图推迟向我的主窗体添加控件,目的是加快它的开始时间。好吧,我在以下异常中运行:

跨线程操作无效: 从线程访问的控件“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 是否为真,但 InvokeRequiered 一直保持“真”。我真的不明白这一点。至少我会期待 *** 异常,因为这是一个递归调用。

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

【问题讨论】:

【参考方案1】:

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

将代码放在 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);
        
    

【讨论】:

【参考方案2】:

你可以这样做......

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

【讨论】:

【参考方案3】:

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

如果我们有这样的形式:

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";

【讨论】:

嗨,腰带。感谢您的快速答复。但我不确定我们是否相互理解。我确实检查了表单是否需要调用调用。在我的情况下,我不更新控件,我只是想在表单上添加一个新控件。 差异不是很大——您必须创建要添加到与 Form 相同的线程中的控件(例如在 InitializeComponent 之后),而不是使用我描述的方法从单独的线程中添加它。 【参考方案4】:

使用线程来添加按钮是非常昂贵的!请改用线程池。

【讨论】:

以上是关于从另一个线程在表单上添加控件的主要内容,如果未能解决你的问题,请参考以下文章

C# 从另一个线程调用 form.show()

当我从另一个表单调用方法时,控件不会更改颜色或文本

清除 WebBrowser 附加控件内容以在用户窗体中重用它

从另一个指令中动态添加 VueJS 指令

Symfony 表单类型从另一个实体添加查询构建器

Xamarin 表单从另一个视图获取数据