C# 在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级
这是一个类。这个类启动了一个线程。用这个线程在form1里添加一个textbox.classClass1{Form1f1;TextBoxtextBox1;publicCl...
这是一个类。这个类启动了一个线程。用这个线程在form1里添加一个textbox.
class Class1
{
Form1 f1;
TextBox textBox1;
public Class1(Form1 f1)
{
this.f1 = f1;
textBox1 = new TextBox();
textBox1.Location = new System.Drawing.Point(94, 189);
textBox1.Name = "textBox1";
textBox1.Size = new System.Drawing.Size(100, 21);
textBox1.TabIndex = 0;
Thread t = new Thread(new ThreadStart(add));
t.Start();
}
public void add()
{
f1.Controls.Add(textBox1);
}
}
---------------------------------------------------------------
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
}
private void Form1_Load(object sender, EventArgs e)
{
Class1 c = new Class1(this);
}
这是主窗体的代码。new了一个Class1的对象,并把自己的实例传过去。
这个时候抛出异常,说 在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级。
请问这是什么意思?该如何解决? 请以本例子举例说明。谢谢
lcg1986 说得不清不楚的 展开
class Class1
{
Form1 f1;
TextBox textBox1;
public Class1(Form1 f1)
{
this.f1 = f1;
textBox1 = new TextBox();
textBox1.Location = new System.Drawing.Point(94, 189);
textBox1.Name = "textBox1";
textBox1.Size = new System.Drawing.Size(100, 21);
textBox1.TabIndex = 0;
Thread t = new Thread(new ThreadStart(add));
t.Start();
}
public void add()
{
f1.Controls.Add(textBox1);
}
}
---------------------------------------------------------------
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
}
private void Form1_Load(object sender, EventArgs e)
{
Class1 c = new Class1(this);
}
这是主窗体的代码。new了一个Class1的对象,并把自己的实例传过去。
这个时候抛出异常,说 在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级。
请问这是什么意思?该如何解决? 请以本例子举例说明。谢谢
lcg1986 说得不清不楚的 展开
4个回答
展开全部
哈哈,这个问题我也碰到过的!
MSDN上的解释说.NETFramework2.0前的时代可以通过子线程在父线程创建控件,当时你上述的代码是正确的。
但是使用线程操作常常会是复杂而且危险的,所以微软在.NETFramework2.0及以后版本都对线程的操作进行了限制。
像你的代码流程应该是这样的:
首先在form1的窗体载入中新建了一个Class1对象并将本身的引用传递进入其构造函数,然后在Class1的构造函数中创建一个线程。该线程所代理的方法事件是本类中的一个add方法。而add方法的内容则是在form1上放一个textbox.
然而这个流程你需要注意的有几个问题:
1.哪个是主线程?所谓主线程是第一个启动的线程,是从main开始的。form1的这个窗体是由主线程创建的。
2.Thread t的线程是什么?t是由主线程创建的,t的操作内容是在由主线程创建的窗体上放一个textbox.
也就是说,t的操作是跨线程的窗体操作。虽然楼主把CheckForIllegalCrossThreadCalls 设置成了false,但是还存在在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级这个异常。
这个问题说实话我也不懂,不好说什么。可能微软禁止了一个线程在另一个线程上添加自己的控件,因为这种做法着实不安全。
至于解决办法:
1.不要线程,只在一个主线程中操作。此时你在class1中添加控件也好,在form1中写个方法来添加控件也好,都是可行的。
2.通过代理来实现。在对form1对象的操作中
if(form1.InvokeRequired)
{
form1.Invoke(d);//d为在主线程中创建的代理引用
//d所代理的方法应该是添加控件的内容
}
else
{
form1.Controls.add(textBox1);//直接使用
}
//代码
class Class1
{
Form1 f1;
TextBox textBox1;
delegate void addDelegate();
addDelegate d;
public Class1(Form1 f1)
{
this.f1 = f1;
d=new addDelegate(f1.add());//此处的add是在form1中的方法
Thread t = new Thread(new ThreadStart(add));
t.Start();
}
public void add()
{
if(f1.InvokeRequired)
{
f1.Invoke(d); //使用代理
}
else
{
f1.Controls.add(new TextBox());//...直接调用
}
}
}
楼主可以在MSDN上查找 “线程处理[windows窗体]”,上面有很详细的描述。
在下也是菜鸟一只,有错误请楼下的朋友指出
MSDN上的解释说.NETFramework2.0前的时代可以通过子线程在父线程创建控件,当时你上述的代码是正确的。
但是使用线程操作常常会是复杂而且危险的,所以微软在.NETFramework2.0及以后版本都对线程的操作进行了限制。
像你的代码流程应该是这样的:
首先在form1的窗体载入中新建了一个Class1对象并将本身的引用传递进入其构造函数,然后在Class1的构造函数中创建一个线程。该线程所代理的方法事件是本类中的一个add方法。而add方法的内容则是在form1上放一个textbox.
然而这个流程你需要注意的有几个问题:
1.哪个是主线程?所谓主线程是第一个启动的线程,是从main开始的。form1的这个窗体是由主线程创建的。
2.Thread t的线程是什么?t是由主线程创建的,t的操作内容是在由主线程创建的窗体上放一个textbox.
也就是说,t的操作是跨线程的窗体操作。虽然楼主把CheckForIllegalCrossThreadCalls 设置成了false,但是还存在在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级这个异常。
这个问题说实话我也不懂,不好说什么。可能微软禁止了一个线程在另一个线程上添加自己的控件,因为这种做法着实不安全。
至于解决办法:
1.不要线程,只在一个主线程中操作。此时你在class1中添加控件也好,在form1中写个方法来添加控件也好,都是可行的。
2.通过代理来实现。在对form1对象的操作中
if(form1.InvokeRequired)
{
form1.Invoke(d);//d为在主线程中创建的代理引用
//d所代理的方法应该是添加控件的内容
}
else
{
form1.Controls.add(textBox1);//直接使用
}
//代码
class Class1
{
Form1 f1;
TextBox textBox1;
delegate void addDelegate();
addDelegate d;
public Class1(Form1 f1)
{
this.f1 = f1;
d=new addDelegate(f1.add());//此处的add是在form1中的方法
Thread t = new Thread(new ThreadStart(add));
t.Start();
}
public void add()
{
if(f1.InvokeRequired)
{
f1.Invoke(d); //使用代理
}
else
{
f1.Controls.add(new TextBox());//...直接调用
}
}
}
楼主可以在MSDN上查找 “线程处理[windows窗体]”,上面有很详细的描述。
在下也是菜鸟一只,有错误请楼下的朋友指出
展开全部
每个控件都有自己的所属线程,MS基于安全考虑.不允许跨线程访问控件..
所以这个地方要使用委托来切换到主线程来创建并增加控件.
Control类有个InvokeRequire来判断是否需要切换线程
用委托完成:
public delegate void Deal();
private Deal deal = new Deal();
在Form_Load()里面加上
deal+= takepicturefunction;
线程函数中
{
if(InvokeRequire)
{
this.Invoke(deal);
}
}
所以这个地方要使用委托来切换到主线程来创建并增加控件.
Control类有个InvokeRequire来判断是否需要切换线程
用委托完成:
public delegate void Deal();
private Deal deal = new Deal();
在Form_Load()里面加上
deal+= takepicturefunction;
线程函数中
{
if(InvokeRequire)
{
this.Invoke(deal);
}
}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
控件不能跨线程操作
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
我不明白,楼主搞这么复杂为了什么.
你们都学得很高深.
你不如说个意图来听听,有没有更简单的方法.
你们都学得很高深.
你不如说个意图来听听,有没有更简单的方法.
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询