using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;namespace ResearchControl
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private delegate void AddControlsInvoker(System.Windows.Forms.Control[] controls); private System.Collections.ArrayList threadList; private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null; public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent(); //
// TODO: Add any constructor code after InitializeComponent call
//
threadList = new System.Collections.ArrayList();
} /// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null) 
{
components.Dispose();
}
}
base.Dispose( disposing );
} #region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.SuspendLayout();
// 
// panel1
// 
this.panel1.Location = new System.Drawing.Point(0, 40);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(584, 424);
this.panel1.TabIndex = 0;
// 
// button1
// 
this.button1.Location = new System.Drawing.Point(24, 16);
this.button1.Name = "button1";
this.button1.TabIndex = 1;
this.button1.Text = "Control1";
this.button1.Click += new System.EventHandler(this.button1_Click);
// 
// button2
// 
this.button2.Location = new System.Drawing.Point(128, 16);
this.button2.Name = "button2";
this.button2.TabIndex = 2;
this.button2.Text = "Control2";
this.button2.Click += new System.EventHandler(this.button2_Click);
// 
// button3
// 
this.button3.Location = new System.Drawing.Point(232, 16);
this.button3.Name = "button3";
this.button3.TabIndex = 3;
this.button3.Text = "Control3";
this.button3.Click += new System.EventHandler(this.button3_Click);
// 
// Form1
// 
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(584, 461);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false); }
#endregion /// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() 
{
Application.Run(new Form1());
} private void button1_Click(object sender, System.EventArgs e)
{
Thread thread = null;
for(int i = threadList.Count - 1; i >= 0; i--)
{
thread = (Thread)threadList[i];
if (thread.IsAlive)
thread.Abort();
threadList.RemoveAt(i);
} panel1.Controls.Clear(); ThreadStart threadStart = new ThreadStart(InitializeControl11);
thread = new Thread(threadStart);
thread.Start();
threadList.Add(thread); threadStart = new ThreadStart(InitializeControl12);
thread = new Thread(threadStart);
thread.Start();
threadList.Add(thread);
} private void button2_Click(object sender, System.EventArgs e)
{
Label waitLabel = new Label();
waitLabel.Location = new System.Drawing.Point(160, 64);
waitLabel.Size = new System.Drawing.Size(288, 23);
waitLabel.Name = "label1";
waitLabel.TabIndex = 0;
waitLabel.Text = "Waiting for intialize controls...";

panel1.Controls.Add(waitLabel);
} private void button3_Click(object sender, System.EventArgs e)
{

} private void AddControls(System.Windows.Forms.Control[] controls)
{
panel1.Controls.AddRange(controls);
}

解决方案 »

  1.   

    private void InitializeControl11()
    {
    System.Windows.Forms.Control[] controls = null; Label waitLabel = new Label();
    waitLabel.Location = new System.Drawing.Point(160, 64);
    waitLabel.Size = new System.Drawing.Size(288, 23);
    waitLabel.Name = "label1";
    waitLabel.TabIndex = 0;
    waitLabel.Text = "Waiting for intialize controls...";

    controls = new System.Windows.Forms.Control[] { waitLabel }; lock(panel1)
    {
    // panel1.SuspendLayout();
    panel1.Invoke(new AddControlsInvoker(AddControls), new object[] {controls});
    // panel1.ResumeLayout();
    }
    #region
    // 
    // label1
    // 
    Label label1 = new Label();
    label1.Location = new System.Drawing.Point(32, 32);
    label1.Name = "label1";
    label1.TabIndex = 0;
    label1.Text = "label1";
    // 
    // label2
    // 
    Label label2 = new Label();
    label2.Location = new System.Drawing.Point(170, 32);
    label2.Name = "label2";
    label2.TabIndex = 1;
    label2.Text = "label2";
    // 
    // label3
    // 
    Label label3 = new Label();
    label3.Location = new System.Drawing.Point(308, 32);
    label3.Name = "label3";
    label3.TabIndex = 2;
    label3.Text = "label3";
    // 
    // label4
    // 
    Label label4 = new Label();
    label4.Location = new System.Drawing.Point(446, 32);
    label4.Name = "label4";
    label4.TabIndex = 3;
    label4.Text = "label4";
    // 
    // textBox1
    // 
    TextBox textBox1 = new TextBox();
    textBox1.Location = new System.Drawing.Point(32, 96);
    textBox1.Name = "textBox1";
    textBox1.TabIndex = 4;
    textBox1.Text = "textBox1";
    // 
    // textBox2
    // 
    TextBox textBox2 = new TextBox();
    textBox2.Location = new System.Drawing.Point(170, 96);
    textBox2.Name = "textBox2";
    textBox2.TabIndex = 5;
    textBox2.Text = "textBox2";
    // 
    // textBox3
    // 
    TextBox textBox3 = new TextBox();
    textBox3.Location = new System.Drawing.Point(308, 96);
    textBox3.Name = "textBox3";
    textBox3.TabIndex = 6;
    textBox3.Text = "textBox3";
    // 
    // textBox4
    // 
    TextBox textBox4 = new TextBox();
    textBox4.Location = new System.Drawing.Point(446, 96);
    textBox4.Name = "textBox4";
    textBox4.TabIndex = 7;
    textBox4.Text = "textBox4";
    #endregion controls = new System.Windows.Forms.Control[] { label1, label2, label3, label4,
    textBox1, textBox2, textBox3, textBox4};
    lock(panel1)
    {
    // panel1.SuspendLayout();
    panel1.Invoke(new AddControlsInvoker(AddControls), new object[] {controls});
    panel1.Controls.Remove(waitLabel);
    // panel1.ResumeLayout();
    }
    }
    private void InitializeControl12()
    {
    System.Windows.Forms.Control[] controls = null; Label waitLabel = new Label();
    waitLabel.Location = new System.Drawing.Point(152, 312);
    waitLabel.Size = new System.Drawing.Size(288, 23);
    waitLabel.Name = "label1";
    waitLabel.TabIndex = 0;
    waitLabel.Text = "Waiting for intialize controls...";

    controls = new System.Windows.Forms.Control[] { waitLabel }; lock(panel1)
    {
    // panel1.SuspendLayout();
    panel1.Invoke(new AddControlsInvoker(AddControls), new object[] {controls});
    // panel1.ResumeLayout();
    }
    #region
    // 
    // label1
    // 
    Label label1 = new Label();
    label1.Location = new System.Drawing.Point(24, 280);
    label1.Name = "label1";
    label1.TabIndex = 0;
    label1.Text = "label1";
    // 
    // label2
    // 
    Label label2 = new Label();
    label2.Location = new System.Drawing.Point(160, 280);
    label2.Name = "label2";
    label2.TabIndex = 1;
    label2.Text = "label2";
    // 
    // label3
    // 
    Label label3 = new Label();
    label3.Location = new System.Drawing.Point(296, 280);
    label3.Name = "label3";
    label3.TabIndex = 2;
    label3.Text = "label3";
    // 
    // label4
    // 
    Label label4 = new Label();
    label4.Location = new System.Drawing.Point(440, 280);
    label4.Name = "label4";
    label4.TabIndex = 3;
    label4.Text = "label4";
    // 
    // textBox1
    // 
    TextBox textBox1 = new TextBox();
    textBox1.Location = new System.Drawing.Point(24, 344);
    textBox1.Name = "textBox1";
    textBox1.TabIndex = 4;
    textBox1.Text = "textBox1";
    // 
    // textBox2
    // 
    TextBox textBox2 = new TextBox();
    textBox2.Location = new System.Drawing.Point(160, 344);
    textBox2.Name = "textBox2";
    textBox2.TabIndex = 5;
    textBox2.Text = "textBox2";
    // 
    // textBox3
    // 
    TextBox textBox3 = new TextBox();
    textBox3.Location = new System.Drawing.Point(296, 344);
    textBox3.Name = "textBox3";
    textBox3.TabIndex = 6;
    textBox3.Text = "textBox3";
    // 
    // textBox4
    // 
    TextBox textBox4 = new TextBox();
    textBox4.Location = new System.Drawing.Point(440, 344);
    textBox4.Name = "textBox4";
    textBox4.TabIndex = 7;
    textBox4.Text = "textBox4"; #endregion controls = new System.Windows.Forms.Control[] { label1, label2, label3, label4,
    textBox1, textBox2, textBox3, textBox4};
    lock(panel1)
    {
    panel1.SuspendLayout();
    panel1.Invoke(new AddControlsInvoker(AddControls), new object[] {controls});
    panel1.Controls.Remove(waitLabel);
    panel1.ResumeLayout();
    }
    }
    }
    }
      

  2.   

    如果函数换成一下形式将运行正常
    private void AddControls(System.Windows.Forms.Control[] controls)
    {
    Label waitLabel = new Label();
    waitLabel.Location = new System.Drawing.Point(160, 64);
    waitLabel.Size = new System.Drawing.Size(288, 23);
    waitLabel.Name = "label1";
    waitLabel.TabIndex = 0;
    waitLabel.Text = "Waiting for intialize controls...";

    panel1.Controls.AddRange(new System.Windows.Forms.Control[] { waitLabel });
    }
      

  3.   

    Windows GUI程序设计的一般规则是:
    1) 由单个线程生成窗口,极其所有子窗口和控件。
    2) 这个线程作为整个窗口结构的owner,控制窗口(和子窗口)的消息循环。
    3)仅有这个线程可以直接安全的访问控件,其他线程必须通过某种线程通信机制来访问控件。(在.NET中,该线程可以调用控件的成员方法,而其他线程必须使用Control.Invoke)。你上面代码的问题是不符合这种基本要求:不能在两个子线程中为窗口添加新的控件,而应该使用某种线程通信,通知UI线程创建这些控件。
      

  4.   

    Control.Invoke是同步线程方法调用,也就是说有主线程执行Invoke中的方法,从而使线程安全,这是我们都知道的。但是当Invoke调用时,主线程阻塞,你的Invoke调用也将堵塞,这是我们应该用BeginInvoke(无等待返回)的方法,或者应该不要让主线程阻塞,即DoEvents这样的相应消息。ok
      

  5.   

    各位大虾,谢谢你们的关注
    to  sqhua(拉长弓兮射天狼):程序其实不长,有兴趣的话可以按照我上面说的方法在你的机器上试试,大部分创建控件的方法可以缩起来不看。to qqchen79(知秋一叶 [MSMVP]):你的答复很有道理,但是我认为:
    1。虽然控件的构造是在其他线程里完成的,但真正完成街面上的工作是在主线程完成的,而线程退出并不会销毁对象,这个对显示或者Control.Invoke有影响吗?
    2。我现在要做的就是要在其他几个线程里完成控件的创建的研究工作,为什么我执行一次Control.Invoke就会正常呢?会带来什么负面或不可预测的影响吗(除消息之外)? to ssdjmcj8048(不爱我的我不爱): 这只是个同步异步的问题,两种情况都试过,结果一样。 再问个问题,在其他线程里访问控件都必须用Control.Invoke吗?很多操作,比如Panel.Controls.Remove,可以在其他线程里完成,结果也正常,会不会有什么不可预测的问题呢?
      

  6.   

    >> 1。虽然控件的构造是在其他线程里完成的,但真正完成街面上的工作是在主线程完成的,而线程退出并不会销毁对象,这个对显示或者Control.Invoke有影响吗?问题是控件同时也是COM对象,并且是STA的对象,所以对象本身无法保证线程访问的安全性,并且创建对象的线程会和控件建立起某种联系。而父窗口和其中的控件肯定需要进行通信,在你的情况下任何这种通信都会存在线程问题。>> 2。我现在要做的就是要在其他几个线程里完成控件的创建的研究工作,为什么我执行一次Control.Invoke就会正常呢?会带来什么负面或不可预测的影响吗(除消息之外)? 既然是线程同步问题,就不能用一次甚至n次的结果来说明问题。该出错的,迟早会出错。>>  再问个问题,在其他线程里访问控件都必须用Control.Invoke吗?很多操作,比如Panel.Controls.Remove,可以在其他线程里完成,结果也正常,会不会有什么不可预测的问题呢?必须用Control.Invoke。和上面一个问题相同,一次正常不能说明问题。