InvokeHelper,让跨线程访问/修改主界面控件不再麻烦(转)
http://bbs.csdn.net/topics/390162519
?
事實(shí)上,本文內(nèi)容很簡(jiǎn)單且淺顯,所以取消前戲,直接開(kāi)始。。
源代碼:在本文最后
這里是一張動(dòng)畫(huà),演示在多線程(無(wú)限循環(huán)+Thread.Sleep)情況下主界面操作不受影響。
多線程是一種提高程序運(yùn)行效率和性能的常用技術(shù)。隨著我們學(xué)習(xí)工作的深入,在編程中或多或少會(huì)涉及到需要多線程的情況。多數(shù)時(shí)候,我們的操作模式是后臺(tái)線程中處理數(shù)據(jù),計(jì)算結(jié)果,然后在前臺(tái)界面(GUI)中更新顯示。
在.NET?Framework中,為了保證線程安全,避免出現(xiàn)訪問(wèn)競(jìng)爭(zhēng)等問(wèn)題,是不允許跨線程訪問(wèn)窗體控件的。如果強(qiáng)行訪問(wèn),則會(huì)引發(fā)InvalidOperationException無(wú)效操作異常,如下圖:
為了實(shí)現(xiàn)跨線程訪問(wèn)控件,.NET?Framework為每個(gè)控件提供了InvokeRequired屬性和Invoke方法。使用這些技巧,就可以實(shí)現(xiàn)我們?cè)谄渌€程中直接修改界面的需要??雌饋?lái)似乎很簡(jiǎn)單,但實(shí)際每次調(diào)用都有不少代碼需要編寫(xiě),還需要自行處理各種異常。下面是典型的調(diào)用例子:
| 1 2 3 4 5 6 7 8 9 10 11 | public?void?DoWork()?? {?? ????if?(control.InvokeRequired)?? ????{?? ????????control.Invoke(DoWork);?? ????}?? ????else?? ????{?? ????????//?do?work?? ????}?? }?? |
為了便于使用,我封裝了實(shí)現(xiàn)細(xì)節(jié),在這里給出一個(gè)InvokeHelper類,使用該類即可方便地實(shí)現(xiàn)跨線程調(diào)用主界面控件方法、獲取/設(shè)置控件屬性等功能。
該類實(shí)現(xiàn)非常簡(jiǎn)單,有效代碼約150行,主要有以下3個(gè)方法:
1.Invoke
該方法可以調(diào)用主界面控件的某個(gè)方法,并返回方法執(zhí)行結(jié)果。用法如下:
| 1 | InvokeHelper.Invoke(<控件>,?"<方法名稱>",?<參數(shù)>);?? |
其中“參數(shù)”為參數(shù)列表,支持0個(gè)或多個(gè)參數(shù)。
2.Get
該方法可以獲取主界面控件的某個(gè)屬性。用法如下:
| 1 | InvokeHelper.Get(<控件>,?"<屬性名稱>");?? |
3.Set
該方法可以設(shè)置主界面控件的某個(gè)屬性。用法如下:
| 1 | InvokeHelper.Set(<控件>,?"<屬性名稱>",?<屬性值>);?? |
下面是整個(gè)類的實(shí)現(xiàn)代碼。最后是一個(gè)演示用的例子。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | /*******************************************************************************? ?*?InvokeHelper.cs? ?*?A?thread-safe?control?invoker?helper?class.? ?*?-----------------------------------------------------------------------------? ?*?Project:Conmajia.Controls? ?*?Author:Conmajia? ?*?Url:conmajia@gmail.com? ?*?History:? ?*??????4th?Aug.,?2012? ?*??????Added?support?for?"Non-control"?controls?(such?as?ToolStripItem).? ?*??????? ?*??????4th?Aug.,?2012? ?*??????Initiated.? ?******************************************************************************/?? using?System;?? using?System.Collections.Generic;?? using?System.Reflection;?? using?System.Text;?? using?System.Windows.Forms;?? ??? namespace?InvokerHelperDemo?? {?? ????///?<summary>?? ????///?A?thread-safe?control?invoker?helper?class.?? ????///?</summary>?? ????public?class?InvokeHelper?? ????{?? ????????#region?delegates?? ????????private?delegate?object?MethodInvoker(Control?control,?string?methodName,?params?object[]?args);?? ??? ????????private?delegate?object?PropertyGetInvoker(Control?control,?object?noncontrol,?string?propertyName);?? ????????private?delegate?void?PropertySetInvoker(Control?control,?object?noncontrol,?string?propertyName,?object?value);?? ????????#endregion?? ?? ????????#region?static?methods?? ????????//?helpers?? ????????private?static?PropertyInfo?GetPropertyInfo(Control?control,?object?noncontrol,?string?propertyName)?? ????????{?? ????????????if?(control?!=?null?&&?!string.IsNullOrEmpty(propertyName))?? ????????????{?? ????????????????PropertyInfo?pi?=?null;?? ????????????????Type?t?=?null;?? ??? ????????????????if?(noncontrol?!=?null)?? ????????????????????t?=?noncontrol.GetType();?? ????????????????else?? ????????????????????t?=?control.GetType();?? ??? ????????????????pi?=?t.GetProperty(propertyName);?? ??? ????????????????if?(pi?==?null)?? ????????????????????throw?new?InvalidOperationException(?? ????????????????????????string.Format(?? ????????????????????????"Can't?find?property?{0}?in?{1}.",?? ????????????????????????propertyName,?? ????????????????????????t.ToString()?? ????????????????????????));?? ??? ????????????????return?pi;?? ????????????}?? ????????????else?? ????????????????throw?new?ArgumentNullException("Invalid?argument.");?? ????????}?? ??? ????????//?outlines?? ????????public?static?object?Invoke(Control?control,?string?methodName,?params?object[]?args)?? ????????{?? ????????????if?(control?!=?null?&&?!string.IsNullOrEmpty(methodName))?? ????????????????if?(control.InvokeRequired)?? ????????????????????return?control.Invoke(?? ????????????????????????new?MethodInvoker(Invoke),?? ????????????????????????control,?? ????????????????????????methodName,?? ????????????????????????args?? ????????????????????????);?? ????????????????else?? ????????????????{?? ????????????????????MethodInfo?mi?=?null;?? ??? ????????????????????if?(args?!=?null?&&?args.Length?>?0)?? ????????????????????{?? ????????????????????????Type[]?types?=?new?Type[args.Length];?? ????????????????????????for?(int?i?=?0;?i?<?args.Length;?i++)?? ????????????????????????{?? ????????????????????????????if?(args[i]?!=?null)?? ????????????????????????????????types[i]?=?args[i].GetType();?? ????????????????????????}?? ??? ????????????????????????mi?=?control.GetType().GetMethod(methodName,?types);?? ????????????????????}?? ????????????????????else?? ????????????????????????mi?=?control.GetType().GetMethod(methodName);?? ??? ????????????????????//?check?method?info?you?get?? ????????????????????if?(mi?!=?null)?? ????????????????????????return?mi.Invoke(control,?args);?? ????????????????????else?? ????????????????????????throw?new?InvalidOperationException("Invalid?method.");?? ????????????????}?? ????????????else?? ????????????????throw?new?ArgumentNullException("Invalid?argument.");?? ????????}?? ??? ????????public?static?object?Get(Control?control,?string?propertyName)?? ????????{?? ????????????return?Get(control,?null,?propertyName);?? ????????}?? ????????public?static?object?Get(Control?control,?object?noncontrol,?string?propertyName)?? ????????{?? ????????????if?(control?!=?null?&&?!string.IsNullOrEmpty(propertyName))?? ????????????????if?(control.InvokeRequired)?? ????????????????????return?control.Invoke(new?PropertyGetInvoker(Get),?? ????????????????????????control,?? ????????????????????????noncontrol,?? ????????????????????????propertyName?? ????????????????????????);?? ????????????????else?? ????????????????{?? ????????????????????PropertyInfo?pi?=?GetPropertyInfo(control,?noncontrol,?propertyName);?? ????????????????????object?invokee?=?(noncontrol?==?null)???control?:?noncontrol;?? ??? ????????????????????if?(pi?!=?null)?? ????????????????????????if?(pi.CanRead)?? ????????????????????????????return?pi.GetValue(invokee,?null);?? ????????????????????????else?? ????????????????????????????throw?new?FieldAccessException(?? ????????????????????????????????string.Format(?? ????????????????????????????????"{0}.{1}?is?a?write-only?property.",?? ????????????????????????????????invokee.GetType().ToString(),?? ????????????????????????????????propertyName?? ????????????????????????????????));?? ??? ????????????????????return?null;?? ????????????????}?? ????????????else?? ????????????????throw?new?ArgumentNullException("Invalid?argument.");?? ????????}?? ??? ????????public?static?void?Set(Control?control,?string?propertyName,?object?value)?? ????????{?? ????????????Set(control,?null,?propertyName,?value);?? ????????}?? ????????public?static?void?Set(Control?control,?object?noncontrol,?string?propertyName,?object?value)?? ????????{?? ????????????if?(control?!=?null?&&?!string.IsNullOrEmpty(propertyName))?? ????????????????if?(control.InvokeRequired)?? ????????????????????control.Invoke(new?PropertySetInvoker(Set),?? ????????????????????????control,?? ????????????????????????noncontrol,?? ????????????????????????propertyName,?? ????????????????????????value?? ????????????????????????);?? ????????????????else?? ????????????????{?? ????????????????????PropertyInfo?pi?=?GetPropertyInfo(control,?noncontrol,?propertyName);?? ????????????????????object?invokee?=?(noncontrol?==?null)???control?:?noncontrol;?? ??? ????????????????????if?(pi?!=?null)?? ????????????????????????if?(pi.CanWrite)?? ????????????????????????????pi.SetValue(invokee,?value,?null);?? ????????????????????????else?? ????????????????????????????throw?new?FieldAccessException(?? ????????????????????????????????string.Format(?? ????????????????????????????????"{0}.{1}?is?a?read-only?property.",?? ????????????????????????????????invokee.GetType().ToString(),?? ????????????????????????????????propertyName?? ????????????????????????????????));?? ????????????????}?? ????????????else?? ????????????????throw?new?ArgumentNullException("Invalid?argument.");?? ????????}?? ????????#endregion?? ????}?? }?? |
下面是一個(gè)演示用的例子。在該例子中,創(chuàng)建了一個(gè)永久循環(huán)的線程,該線程每隔500毫秒修改一次界面顯示。主要代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | Thread?t;?? private?void?button1_Click(object?sender,?EventArgs?e)?? {?? ????if?(t?==?null)?? ????{?? ????????t?=?new?Thread(multithread);?? ????????t.Start();?? ????????label4.Text?=?string.Format(?? ????????????"Thread?state:\n{0}",?? ????????????t.ThreadState.ToString()?? ????????????);?? ????}?? }?? ??? public?void?DoWork(string?msg)?? {?? ????this.label3.Text?=?string.Format("Invoke?method:?{0}",?msg);?? }?? ??? int?count?=?0;?? void?multithread()?? {?? ????while?(true)?? ????{?? ????????InvokeHelper.Set(this.label1,?"Text",?string.Format("Set?value:?{0}",?count));?? ????????InvokeHelper.Set(this.label1,?"Tag",?count);?? ????????string?value?=?InvokeHelper.Get(this.label1,?"Tag").ToString();?? ????????InvokeHelper.Set(this.label2,?"Text",?? ????????????string.Format("Get?value:?{0}",?value));?? ??? ????????InvokeHelper.Invoke(this,?"DoWork",?value);?? ??? ????????Thread.Sleep(500);?? ????????count++;?? ????}?? }?? |
詳細(xì)代碼請(qǐng)參閱源代碼。運(yùn)行后效果正常,盡管線程t是無(wú)限循環(huán)的線程,但主界面并不受其阻塞,操作一切正常。
源代碼:點(diǎn)擊下載
轉(zhuǎn)載于:https://www.cnblogs.com/zzh1236/p/3461837.html
總結(jié)
以上是生活随笔為你收集整理的InvokeHelper,让跨线程访问/修改主界面控件不再麻烦(转)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 性能面试2
- 下一篇: Daily Scrum02 12.09