跨线程操作控件的Invoke怎么理解

hailun 2011-12-06 08:16:19

private delegate void InvokeCallback(string msg);

void m_comm_MessageEvent(string msg)
{
if(txtMessage.InvokeRequired) //InvokeRequired什么意思
{
InvokeCallbackmsgCallback = new InvokeCallback(m_comm_MessageEvent); //这个参数为什么是调用的方法名,而不是(如果有a(),b(),c()等方法)调用的a或b或是c呢?
txtMessage.Invoke(msgCallback, new object[] { msg });//怎么理解这句呢?
}
else
{
txtMessage.Text = msg; //还有这里
}
}
...全文
192 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
niaoked 2011-12-06
  • 打赏
  • 举报
回复
Invoke、BeginInvoke实质上就是调用了Win32的SendMessage和PostMessage。
采用这种方式以确保在跨线程控制控件时的线程安全。
wushuai1346 2011-12-06
  • 打赏
  • 举报
回复
有些时候上下文的执行结果不同,这个时候你需要进行判断需要用哪个方法去处理这种情况,这个时候使用委托会使逻辑更加清晰。程序设计的时候,思考的角度不同,使用的技术权重也就会有所差异。我是这样理解的,不足之处请各位大神指正。
hailun 2011-12-06
  • 打赏
  • 举报
回复
我也想给分,但没答案啊
q198708wyp 2011-12-06
  • 打赏
  • 举报
回复
我要分数
hailun 2011-12-06
  • 打赏
  • 举报
回复
继续期待
hailun 2011-12-06
  • 打赏
  • 举报
回复
比如我想把
txtMessage.Text = msg; //msg=“谢谢大家的回复帮助”,难道txtMessage.Invoke(msgCallback, new object[] { msg });//就是等同于else里的txtMessage.Text = msg; 吗?如果是这样理解的话

那么txtMessage.Invoke(msgCallback, new object[] { msg });为什么不是txtMessage.enable=true(false)或是是txtMessage.readonly=true(false)或是对其他属性的操作,而只是针对text的属性呢?
hailun 2011-12-06
  • 打赏
  • 举报
回复
我的理解是本来就是调用m_comm_MessageEvent这个方法来执行,那么在该方法里创建委托对象然后在回调这个方法理解不了,如果是在这里调用a,b,c其他方法可以理解a,b,c里做了哪些事情,而该方法里只是创建了委托对象并没有做该做的事情,所以没有理解
我的意思就是
a(){
txtMessage.Text = msg; //这里执行了
}
而m_comm_MessageEvent只是创建委托对象,而且是在else里执行的txtMessage.Text = msg; 如果if为真,那么txtMessage.Text = msg; //这句并没有执行啊,我们不就是想要它执行吗?
宝_爸 2011-12-06
  • 打赏
  • 举报
回复
InvokeCallbackmsgCallback = new InvokeCallback(m_comm_MessageEvent); //这个参数为什么是调用的方法名,而不是(如果有a(),b(),c()等方法)调用的a或b或是c呢?

这就是delegete的使用方法,如果想同步调用,就InvokeCallbackmsgCallback("asdfas");
研究员 2011-12-06
  • 打赏
  • 举报
回复
可以.我在上面已经讲的很清楚了,麻烦你把我写的文字再认真看一次。

另外,if(txtMessage.InvokeRequired) 这个判断,是不对的。原因很复杂,你以后会明白的。
直接按我上面讲的直接去写就OK了。
hailun 2011-12-06
  • 打赏
  • 举报
回复
谢谢以上所有朋友的回复

private delegate void InvokeCallback(string msg);

void m_comm_MessageEvent(string msg)
{
if(txtMessage.InvokeRequired)
{
InvokeCallbackmsgCallback = new InvokeCallback(a); //这里改成a可以吗?
txtMessage.Invoke(msgCallback, new object[] { msg });
}
else
{
txtMessage.Text = msg;
}
}

private void a(){
txtMessage.Text = "调用a方法可以吗?";
}
绿领巾童鞋 2011-12-06
  • 打赏
  • 举报
回复
原来是这样啊
se7en 2011-12-06
  • 打赏
  • 举报
回复
其实简单的很简单,说复杂了也很复杂 。
铜臂阿铁木 2011-12-06
  • 打赏
  • 举报
回复

简单的理解是,当前想要操作控件的线程直接去操作的话可能会有线程安全问题,然后就告诉主线程(Invoke):你来做,我做不了
tglgx 2011-12-06
  • 打赏
  • 举报
回复
InvokeRequired表示该控件是否需要通过Invoke才能进行操作
Invoke的意思就是将委托交给当前控件所在线程执行


由于线程安全性问题,你在别的线程直接 txtMessage.Text = msg是会有异常的

所以这里写了 m_comm_MessageEvent这个方法,先判断下是否需要Invoke,如果需要则调用对应控件的Invoke来执行本方法。
研究员 2011-12-06
  • 打赏
  • 举报
回复
阅读以下文字,需要掌握:
A.线程的基本知识。
B.C#的基本知识,以及委托 Delegate 的用法。

1.首先,界面,比如Winform,是由一个线程来维护的。我们暂且称这个线程为 Thread_UI .
Thread是线程的意思。UI是界面的意思。

2.其次,其他的线程,是不能直接去访问或者操作界面上的控件.
比如,你新建一个线程:Thread_New,然后在这个线程的方法里,写:
......
this.textBox.Text = "我爱研究员";
.....
这样就会产生异常。

3.界面线程Thread_UI,它维护着一个任务列表,如果这个列表里有任务,它就会去执行它。
所以,如果新线程Thread_New要访问界面上的控件,就必须把这个任务,放入界面线程Thread_UI的任务列表里。让Thread_UI去执行。

4.Thread_New创建任务,就需要用到委托Delegate。
public delegate void Delegate_Void();
上面这句话,定义了一个新的委托,它在C++里,实际上是一个函数指针。它没有参数,也没有返回。
delegate是类型,也就是C#中的委托。
void 是返回值。标记为void,也就是它没有返回值。
Delegate_Void,是这个委托类型的名字。用下划线,只是我个人的一种命名方式。
后面有一个括号(),这个是C#里创建自定义委托的写法。
假如,现在我创建一个,参数是两个int,返回值是string,名字为XXX的委托,则是:
public delegate string XXX( int arg_number1, int arg_number2 );

5.有了委托后,我们得定义一个任务:把界面上的textBox的文字,设置为“我爱研究员”。
这个任务的实质就是一个方法:
public void DelegateFunction_SetTextBox( )
{
this.textBox.Text = "我爱研究员";
}
这个大家都能看明白吧?我就不解释了。看不明白?你C#白学了。赶快去找本C#书,重新做人吧。
要注意一点就是,这个方法的参数与返回值,必须与【4】的自定义委托的参数与返回值要相同。
比如:
委托: public delegate void Delegate_Void();
那么方法就必须是: public void XXXX( ) { ..... };
再如:
委托:public delegate string Delegate_String( int arg_number, string arg_string );
那么方法就必须是: public string YYYY( int arg_number, string arg_string ) { .... };

6.重点来了。现在,Thread_New这个新线程,要通过委托(任务入口),创建一个方法的实例(任务要做的事情),然后把这个委托(任务入口),通过invoke方法,丢给Thread_UI去执行。然后,Thread_UI通过委托(任务入口),找到这个方法(任务要做的事情),并且执行这个方法(任务要做的事情)。

7.例子:Thread_New,要把界面上的TextBox的文本,设置成它想要设置的字符串。
因此,就有了任务要做的事情,也就是方法:
public void SetText( string arg_msg )
{
this.textBox.Text = arg_msg;
}

然后,我们根据这个方法,来定义一个委托:
public delegate void Delegate_Void( string arg_msg );

接着,让Thread_New,来产生一个委托(入口),并且让这个入口指向这个方法:
.....
Delegate_Void newDelegate = new Delegate_Void( this.SetText );
上面这句,Delegate_Void就是刚才我们定义的委托类型的名字。
newDelegate是这个委托类型的实例。
this.SetText便是刚才我们定义的方法,这里,把它作为参数。注意,方法作为参数时,不要加后面的括号。
最后,让Thread_UI来执行它就行了:
this.Invoke( newDelegate, new object[ ] { "我爱研究员~" } );
上面这句的 this,也就是当前环境。在Winform里,this实际上是指向界面,也就指向了界面线程Thread_UI。
this.Invoke( .... ) 实际上就是让 Thread.UI去Invoke(......)
Invoke里的两个参数,第一个参数 newDelegate ,便是刚才我们定义的委托的实例,也就是任务的入口。
第二个参数 new object [ ] { "我爱研究员~" } ,它实际上是一个 object 数组,这个数组里,只有一个值,也就是字符串 "我爱研究员" 。为什么要写出object数组,这个是C#规定的。
如果这个委托没有参数,那么只要这样写就行了: this.Invoke( newDelegate );
如果有多个参数,那就这样写:
this.Invoke( newDelegate, new object [ ] { 参数1, 参数2... } );
最后,Thread_UI就执行它了~~

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧