C#中,在多线程中,为什么子线程操作主界面的某些控件正常,而操作某些控件产生错误? ( 积分: 20 )

  • 主题发起人 mycwcgr_new
  • 开始时间
M

mycwcgr_new

Unregistered / Unconfirmed
GUEST, unregistred user!
C#中,在多线程中,为什么子线程操作主界面的某些控件正常,而操作某些控件产生错误?
在子线程的private void FillListView()操作中,如果执行listBox1.Items.Add(i);则正常,而执行treeView1.Nodes.Add(new TreeNode(i.ToString()));时产生下面的错误,为什么?
“在该控件上执行的操作正被错误的线程调用。必须使用 Control.Invoke 或 Control.begin
Invoke 封送到正确的线程才能执行此操作。”


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
namespace WindowsApplication6
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.TreeView treeView1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.treeView1 = new System.Windows.Forms.TreeView();
this.SuspendLayout();
this.button1.Location = new System.Drawing.Point(104, 192);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);

this.listBox1.ItemHeight = 12;
this.listBox1.Location = new System.Drawing.Point(16, 24);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(112, 112);
this.listBox1.TabIndex = 1;
this.treeView1.ImageIndex = -1;
this.treeView1.Location = new System.Drawing.Point(144, 24);
this.treeView1.Name = "treeView1";
this.treeView1.SelectedImageIndex = -1;
this.treeView1.Size = new System.Drawing.Size(120, 112);
this.treeView1.TabIndex = 2;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.treeView1);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion

[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
ThreadStart worker=new ThreadStart(FillListView);
Thread workThread=new Thread(worker);
workThread.Start();

}
private void FillListView()
{
for(int i=0;i<=50;i++)
{
listBox1.Items.Add(i);
//treeView1.Nodes.Add(new TreeNode(i.ToString()));
}
}

}
}
 
C#中,在多线程中,为什么子线程操作主界面的某些控件正常,而操作某些控件产生错误?
在子线程的private void FillListView()操作中,如果执行listBox1.Items.Add(i);则正常,而执行treeView1.Nodes.Add(new TreeNode(i.ToString()));时产生下面的错误,为什么?
“在该控件上执行的操作正被错误的线程调用。必须使用 Control.Invoke 或 Control.begin
Invoke 封送到正确的线程才能执行此操作。”


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
namespace WindowsApplication6
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.TreeView treeView1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.treeView1 = new System.Windows.Forms.TreeView();
this.SuspendLayout();
this.button1.Location = new System.Drawing.Point(104, 192);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);

this.listBox1.ItemHeight = 12;
this.listBox1.Location = new System.Drawing.Point(16, 24);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(112, 112);
this.listBox1.TabIndex = 1;
this.treeView1.ImageIndex = -1;
this.treeView1.Location = new System.Drawing.Point(144, 24);
this.treeView1.Name = "treeView1";
this.treeView1.SelectedImageIndex = -1;
this.treeView1.Size = new System.Drawing.Size(120, 112);
this.treeView1.TabIndex = 2;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.treeView1);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion

[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
ThreadStart worker=new ThreadStart(FillListView);
Thread workThread=new Thread(worker);
workThread.Start();

}
private void FillListView()
{
for(int i=0;i<=50;i++)
{
listBox1.Items.Add(i);
//treeView1.Nodes.Add(new TreeNode(i.ToString()));
}
}

}
}
 
http://msdn.microsoft.com/library/chs/default.asp
url=/library/chs/vbcon/html/vbconscalabilitymultithreadingincomponents.asp
多线程处理最适合于运行类模块的处理器密集型过程。与其他组件不同的是,从单独的线程直接调用控件中的方法会存在一些问题。影响控件的方法只应该在创建控件的线程上执行。由于从一个线程封送调用并跨线程边界将其发送到另一个线程会耗费大量的系统资源,所以应避免重复调用其他线程上的控件。在最佳情况下,从其他线程直接进行调用将耗费大量资源,进而使应用程序的性能受损。在最坏的情况下,将发生导致应用程序中出现死锁的情况,进而使执行冻结。
不过,在有些情况下,您可能需要通过线程调用控件的方法。例如,您可能要在窗体上调用一个禁用按钮或更新显示的方法来响应某个线程执行的操作。.NET Framework 提供从任何线程都可安全调用的方法,以调用与其他线程所拥有的控件进行交互的方法。Control.Invoke 方法允许同步执行控件上的方法,而 Control.begin
Invoke 方法则初始化异步执行。要使用这些方法,必须用与将调用的方法相同的签名声明委托。然后,您可以通过向要调用的方法提供适当的委托来调用窗体上任何控件的 Invoke 或 begin
Invoke 方法。任何必需的参数都包装在 Object 中,并被传输到该方法。
 
接受答案了.
 
顶部