文章目录
前言
为啥写这个?
因为本人间断性的会进行winform的开发, 对各种跨线程的处理,以及UI的处理.每次都忘记怎么写.都要重新百度,效率很低.
这里记录总结一下.也分项给有需要的朋友 哈哈哈
几个概念
什么是委托delegate
刚开始接触的时候,觉得太TM绕了(我智商低).自己总结一下. 委托就是一个方法行为的集合 , 执行委托 就相当于执行一些列的行为
一个委托可以只有一个方法,可以一个方法都没有,也可以有N个方法
说人话就是 ,委托就是一个代理委托人,我把要执行的任务事情(function)告诉他,他收集好之后,等待我的命令,我让他执行,他就把事情都给我办了.
为什么要委托
- 可以解耦. 只要参数类型一致的方法,都可以塞进一个委托里面.那么在开发者A的角度.我只要执行这个委托就可以了. 具体这个委托要做的动作细节,开发者B自己去实现
- 跨线程UI操作.这个是我用得最多的. 界面卡死,无响应,报错等等,大部分和UI进程阻塞有关. 合理的方法应该是:- 主线程就负责UI界面的调度.- 涉及到耗时的动作,全部扔给线程去异步处理.- 处理完成后,通过invoke委托的方法,来触发UI刷新(因为子线程invoke只能是委托,所以要用委托. 是吗? 我也不确定,哈哈)
- 其他应该还有点别的用处,但是我用不上
直接上代码例子
直接来个最简单的写法
这个目前我认为最简单而已,仅仅是我认为.
即通过lamda表达式 和thread 来实现委托异步回调
//定义委托 作用:回调主界面UIdelegatevoidDelegateHandleUI(String str);privatevoidbtn_Getversion_threadlamda_Click(object sender,EventArgs e){//声明一个线程异步执行Thread t1 =newThread(delegate(){//线程里面执行 耗时的动作JObject jo =getVersion();//耗时动作结束后 通过lamda表达式 直接写逻辑invoke 委托,执行页面UI刷新方法 ;this.Invoke(newDelegateHandleUI((a)=>{
textBox1.Text = a;}),newObject[]{ jo.ToString()});});//执行这个线程
t1.Start();}
这里没有额外声明函数,直接通过lamda去定义了一个委托动作来实现.
稍微复杂完整的写法
//定义委托 作用:回调主界面UIdelegatevoidDelegateHandleUI(String str);privatevoidbtn_Getversion_thread_Click(object sender,EventArgs e){//告诉委托 要委托执行哪个方法DelegateHandleUI delegateHandleUI = UIshow;//声明一个线程异步执行Thread t1 =newThread(delegate(){//线程里面执行 耗时的动作JObject jo =getVersion();//耗时动作结束后 invoke 委托,执行页面UI刷新方法 ;this.Invoke(delegateHandleUI,newObject[]{ jo.ToString()});//delegateHandleUI("888"); 直接这样写 会报 跨线程调用ui控件错误 需要通过上面的 invoke的方式取回调委托});
t1.Start();}publicvoidUIshow(String str){
textBox1.Text = str;}
这里相比上面, 多了一个 预先定义方法,然后将方法绑定到委托的动作
好处是可以类似这样
DelegateHandleUI delegateHandleUI += UIshow1;
DelegateHandleUI delegateHandleUI += UIshow2;
同时塞入多个方法给一个委托. 让委托一次执行多个动作
来个Action的写法
publicpartialclassForm1:Form{delegatevoidDelegateHandleUI(String str);publicForm1(){InitializeComponent();}publicvoidUIshow(String str){
textBox1.Text = str;}/// <summary>/// 这里只是回调 ,一般不同个这里的 IAsyncResult ar 来处理控件/// 这里仍然是线程的方法/// </summary>/// <param name="ar"></param>privatevoidMyAsynCallback(IAsyncResult ar){// 这时候的ar.AsyncState 就是 "123" //textBox1.Text = ar.AsyncState.ToString(); 注意这里仍然是 线程的动作.调用控件会犯法
Console.WriteLine("异步调用结束");// Console.ReadLine();}privatevoidbtn_Getversion_Click(object sender,EventArgs e){Action action =(()=>{#region 需要等待的硬件调用object obj = SiReader.getVerion();JObject jo = JObject.FromObject(obj);#endregion#region 通过委托方法 刷新主线程UIDelegateHandleUI delegateHandleUI =newDelegateHandleUI(UIshow);this.Invoke(delegateHandleUI,newobject[]{ jo.ToString()});#endregion});//必须定义一个AsyncCallback 哪怕不处理任何动作AsyncCallback asyncCallBack =newAsyncCallback(MyAsynCallback);#region 异步执行action
action.BeginInvoke(asyncCallBack,"123");//这里传123 就是看看MyAsynCallback的 ar.AsyncState 能不能获取到123#endregion#region 以下3个写法 等效, 属于同步 不是异步!!//this.BeginInvoke(action); //这样是同步 不是异步!!//this.Invoke(action);//action();#endregion}}
这个稍微麻烦的就是需要实现一个AsyncCallback 方法才能实现异步
有强迫的朋友就别用了
来个Action带入参的写法
privatevoidbtn_Getversion_Click(object sender,EventArgs e){//Action action = (() =>Action<int,int> action =((a,b)=>{#region 需要等待的硬件调用 JObject jo =getVersion();#endregion
Console.WriteLine("测试Action 传参数:"+(a + b).ToString());#region 通过委托方法 刷新主线程UIDelegateHandleUI delegateHandleUI =newDelegateHandleUI(UIshow);this.Invoke(delegateHandleUI,newobject[]{ jo.ToString()});#endregion});//必须定义一个AsyncCallback 哪怕不处理任何动作AsyncCallback asyncCallBack =newAsyncCallback(MyAsynCallback);#region 异步执行action //后面两个参数固定, 第一个 和 第二个 参数为 定义Aciton时候的入参
action.BeginInvoke(3,4,asyncCallBack,"123");//这里传123 就是看看MyAsynCallback的 ar.AsyncState#endregion#region 以下3个写法 等效, 属于同步 不是异步!!//this.BeginInvoke(action); //这样是同步 不是异步!!//this.Invoke(action);//action();#endregion}
类似还有Func的写法,这个和Action类似,只是多了返回值而已,不记录了
版权归原作者 何浩翔 所有, 如有侵权,请联系我们删除。