跨线程访问UI控件时的Lambda表达式

工作中经常会用到跨线程访问UI控件的情况,由于.net本身机制,是不允许在非UI线程访问UI控件的,实际上跨线程访问UI控件还是 将访问UI的操作交给UI线程来处理的,

利用Control.Invoke方法,将操作传递给UI线程,不推荐使用CheckForIllegalCrossThreadCalls = false;

Control.Invoke的签名

//
// 摘要:
// 在拥有此控件的基础窗口句柄的线程上执行指定的委托。
//
// 参数:
// method:
// 包含要在控件的线程上下文中调用的方法的委托。
//
// 返回结果:
// 正在被调用的委托的返回值,或者如果委托没有返回值,则为 null。
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public object Invoke(Delegate method);

但是如果我们利用Lambda表达式的时候,编译会报错。

 

如:

    this.Invoke(() => { this.panel1.Controls.Remove(ucLoading); });

编译报错:无法将Lambda表达式转为System.Delegate类型,因为他不是委托类型

 

The problem the user is seeing is that the Thread ctor accepts a specific delegate -- the ThreadStart delegate.  The C# compiler will check and make sure your anonymous method matches the signature of the ThreadStart delegate and, if so, produces the proper code under-the-covers to create the ThreadStart delegate for you.

But Control.Invoke is typed as accepting a "Delegate".  This means it can accept any delegate-derived type.  The example above shows an anonymous method that has a void return type and takes no parameters.  It's possible to have a number of delegate-derived types that match that signature (such as MethodInvoker and ThreadStart -- just as an example).  Which specific delegate should the C# compiler use?  There's no way for it to infer the exact delegate type so the compiler complains with an error.

也就是说,对于Thread 构造函数来说,由于接受的是一个ThreadStart委托,编译器便可以将匿名函数与ThreadStart委托类型匹配,最后能够正确编译。
而对于Control.Invoke()来说,任何的代理类型都是可接受的,也就是说ThreadStart和MethodInvoker都是可以接受的类型。这样编译器反而不知道应该用哪个代理去匹配匿名函数了,导致了编译错误的发生。

 

我们就得加个委托名了

        this.Invoke(new Action(() => { this.panel1.Controls.Remove(ucLoading); }));

或者

        this.Invoke(new MethodInvoker(() => { this.panel1.Controls.Remove(ucLoading); }));

posted @ 2014-06-19 17:40  大侠的哥哥是菜鸟  阅读(712)  评论(0编辑  收藏  举报