我理解的委托就是具有同样参数和返回值的函数的集合.比如
publicdelegatevoidMyDelegate(intarg);就是这种形式的函数voidMyfuntion(inti);的集合.如何将一个函数加入委托的集合?
MyDelegatedele=newMyDelegate(Myfuntion1);再增加一个
dele+=newMyDelegate(Myfuntion2);...
委托函数dele就是具有整数参数和空返回值的函数Myfuntion1,2的集合.调用这个委托函数dele(1);
就是逐个调用Myfuntion1,2,...一般线程函数的声明和启动
Threadt=newThread(newThreadStart(MyFunction));t.Start();
正是调用了没有参数和返回值的委托函数ThreadStart其中的参数MyFunction是这个委托函数中的一员.很明显这样无法传参数和返回值,那我们该怎么办?
答案就在委托的BeginInvoke()方法上,BeginInvoke()也是(异步)启动一个新线程.例如
MyDelegatedele=newMyDelegate(MyFunction);dele.BeginInvoke(10,\"abcd\");
voidMyFunction(intcount,stringstr);可以实现参数的传递.如何收集线程函数的返回值?
与BeginInvoke对应有个EndInvoke方法,而且运行完毕返回IAsyncResult类型的返回值.这样我们可以这样收集线程函数的返回值MyDelegatedele=IAsyncResultref...
newMyDelegate(MyFunction);=dele.BeginInvoke(10,\"abcd\");
intintresult=dele.EndInvoke(ref);<----收集返回值
MyFunction(intcount,stringstr);<----带参数和返回值的线程函数
提示:\"线程间操作无效:从不是创建控件“XX”的线程访问它\"
一般来说,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程不同的空间,因此想要在子线程来操作窗体上的控件,是不可能简单的通过控件对象名来操作,但是说不能进行操作,微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的件操作。现在用一个用线程控制的进程条来说明,大致的步骤如下:
1.创建Invoke函数,大致如下://////DelegatefunctiontobeinvokedbymainthreadprivatevoidInvokeFun(){if(prgBar.Value<100)prgBar.Value=prgBar.Value+1;}
2.子线程入口函数://////Threadfunctioninterface///privatevoidThreadFun()
{//Createinvokemethodbyspecificfunction
MethodInvokermi=newMethodInvoker(this.InvokeFun);
for(inti=0;i<100;i++){this.BeginInvoke(mi);Thread.Sleep(100);}}3.创建子线程:
ThreadthdProcess=newThread(newThreadStart(ThreadFun));thdProcess.Start();
出现这个问题主要是因为在线程方法中操作了界面上的控件..lstPrime.Items.Add()可以这样改下..//定义一个委托
publicdelegatevoidMyInvoke(stringstr);//定义一个操作界面的方法
privatevoidUpdateUI(stringstr){
//增加项
this.lstPrime.Items.Add(str);}
//在线程的方法中,即你的Generate方法..
//里面只要是涉及到Items.Add操作的都改成如下形式即可..//比如lstPrime.Items.Add(2);改成:MyInvokemi=newMyInvoke(UpdateUI);
this.BeginInvoke(mi,newobject[]{\"2\
============================================================================
BeginInvoke与Invoke的含义[转载]BeginInvoke方法真的是新开一个线程进行异步调用吗?参考以下代码:
publicdelegatevoidtreeinvoke();privatevoidUpdateTreeView(){
MessageBox.Show(System.Threading.Thread.CurrentThread.Name);}
privatevoidbutton1_Click(objectsender,System.EventArgse){
System.Threading.Thread.CurrentThread.Name=\"UIThread\";treeView1.BeginInvoke(newtreeinvoke(UpdateTreeView));}
看看运行结果,弹出的对话框中显示的是UIThread,这说明BeginInvoke所调用的委托根本就是UI线程中执行的。
既然是在UI线程中执行,又何来“异步执行”一说呢?我们再看看下面的代码:
publicdelegatevoidtreeinvoke();privatevoidUpdateTreeView(){
MessageBox.Show(Thread.CurrentThread.Name);}
privatevoidbutton1_Click(objectsender,System.EventArgse){
Thread.CurrentThread.Name=\"UIThread\";
Threadth=newThread(newThreadStart(StartThread));th.Start();}
privatevoidStartThread(){
Thread.CurrentThread.Name=\"WorkThread\";
treeView1.BeginInvoke(newtreeinvoke(UpdateTreeView));}
再看看运行结果,弹出的对话框中显示的还是UIThread,这说明什么?这说明BeginInvoke方法调用的委托无论如何都是在UI线程中执行的。那BeginInvoke究竟有什么用呢?
在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方
是错误的做法,具体的原因可以在看完我的这篇之后看看这篇:在多线程中如何调用Winform,如你是大牛的话就不要看我这篇了,直接看那篇吧,反正那篇文章我没怎么看懂。
Invoke和BeginInvoke就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。
正确的做法是将工作线程中涉及更新界面的代码封装为一个方法,通过Invoke或者BeginInvo去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会。
而所谓的“一面响应操作,一面添加节点”永远只能是相对的,使UI线程的负担不至于太大而因为界面的正确更新始终要通过UI线程去做,我们要做的事情是在工作线程中包揽大部分的运而将对纯粹的界面更新放到UI线程中去做,这样也就达到了减轻UI线程负担的目的了。
而在那段更新树节点的代码中,其实唯一起作用的代码是:System.Threading.Thread.Sleep(100它使UI线程有了处理界面消息的机会,其实数码幽灵将问题复杂化了,只要以下的代码就可以好的工作了。
privatevoidbutton1_Click_(objectsender,System.EventArgse){
TreeNodetn;
for(inti=0;i<100000;i++){
tn=newTreeNode(i.ToString());
this.treeView1.Nodes[0].Nodes.Add(tn);if(i%100==0)Application.DoEvents();}
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- sarr.cn 版权所有 赣ICP备2024042794号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务