2010-02-12 67 views
6

這是我在這個網站上的第一篇文章,我必須說的是,太棒了!在窗體上添加控件,從另一個線程

那麼這是我的問題,我真的希望有人能夠幫助我。

我試圖推遲添加控件到我的主窗體,目標是加快它的開始時間。嗯,我在下面的異常運行:

跨線程操作無效: 控制「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異常,因爲這是一個遞歸調用。

所以,如果有人遇到類似的問題,請你能告訴我我做錯了什麼?

Thanx,Igor!

回答

4

的問題在你的代碼是你要添加兩個按鈕。

將代碼放在else塊的if塊之後。

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); 
     } 
    } 
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"; 
} 
+0

嗨,腰帶。 謝謝你的回答。但我不確定我們是否瞭解對方。我沒有檢查表單是否需要Invoke調用。而在我的情況下,我不更新控件,我只是想在表單上添加一個新控件。 – Gico 2010-02-12 09:42:47

+0

區別不是那麼大 - 你必須創建控件,你想添加在窗體相同的線程(例如在InitializeComponent之後),而不是使用我描述的方法從單獨的線程添加它。 – sashaeve 2010-02-12 10:05:53

0

使用線程添加按鈕非常昂貴!改用ThreadPool。

相關問題