【问题标题】: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 一直保持“真”。我真的不明白这一点。至少我会期待 StackOverflow 异常,因为这是一个递归调用。

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

【问题讨论】:

    标签: c# invoke multithreading


    【解决方案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】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-21
          • 1970-01-01
          相关资源
          最近更新 更多