天天看点

PostSharp - Thread Dispatching(GUI多线程)

在我们的桌面应用程序(不管是winform还是wpf)我们都必须去面对线程的dispatching。在window图形用户系统中像基于.net的winform或者是wpf都有一个唯一的主线程。他们是基于Win32消息循环队列机制处理ui界面的事件(又分为事件的钻取和隧道)、渲染。所以在一个长时间的事件处理中,我们的ui不会得到及时的更新和响应,甚至会出现假死状态。所以在gui编程有这么一条黄金规则:不要再gui主线程处理长时间的应用。对于长时间的处理,我们需要应用在异步线程中,并且通常认为最佳的实践并不是为每一个操作创建一个线程,而是放入线程池队列中。

注:一下代码都分析了winform,但是贴出带带代码为wpf。

       下面是响应UI按钮事件,异步处理方式:

PostSharp - Thread Dispatching(GUI多线程)

private void okbutton_click(object sender, routedeventargs e)

{

    threadpool.queueuserworkitem(

        delegate { this.contact.save(); });

}

PostSharp - Thread Dispatching(GUI多线程)

在这里如果我们需要操作更新UI呢?将会引出一个gui经典exception:你所操作的uI不是该线程创建的。对于这个exception我们的解决方案是:

winform:异常代理调用<code>this.begininvoke</code><code>,</code><code>wpf</code><code>这有绘画线程:</code><code>code</code><code>如下:</code>this.dispatcher.begininvoke。

PostSharp - Thread Dispatching(GUI多线程)

private void okbutton_click( object sender, routedeventargs e )

        delegate

            {

                this.contact.save();

                this.dispatcher.begininvoke( 

                    dispatcherpriority.normal,

                    new action( () =&gt; messagebox.show( getwindow( this ), "saved!" ) ) );

            } );

PostSharp - Thread Dispatching(GUI多线程)

在上面的代码中有很好相似之处,我们能不能简化,使得我们的开发并不需要关心这里的线程技术问题,没有线程的概念化,使得我们只需要关心我们的业务逻辑处理?在面向方向编程,讲究纵向拦截,利用aop,我们可以很好的处理这些问题。特别是postsharp这种静态注入方式,如微软企业库EL这类动态拦截方式,我们不能直接创建new对象,然而我们这里并不能控制窗体的创建。

先看想想我们期望最终如何来这种代码,我对代码很吝啬,不想写太多,写的越少越好,就像jquery口号一样:“write less, do more,”。我想最多加一个attribute吧,必究还是需要标示嘛。期望code如下:

PostSharp - Thread Dispatching(GUI多线程)

[onworkerthread]

    this.contact.save();

    this.showmessage( "contact saved!" );

[onguithread]

void showmessage(string message)

    messagebox.show(getwindow(this), message);

PostSharp - Thread Dispatching(GUI多线程)

在下面我们将引入两个个attribute:onworkerthreadattribute,onguithreadattribute,实现他们。首先我们需要的是方法的拦截所以肯定是选择methodinterceptionaspect基类。下面我们实现简单的异常线程onworkerthreadattribute:

PostSharp - Thread Dispatching(GUI多线程)

serializable]

public class onworkerthreadattribute : methodinterceptionaspect

    public override void oninvoke( methodinterceptionargs args )

    {

        threadpool.queueuserworkitem( state =&gt; args.proceed() );

    }

PostSharp - Thread Dispatching(GUI多线程)

下面我们将实现gui线程onguithreadattribute,与上面不同的是稍微复杂一些,我们需要考虑我们的当前线程是不是主线程,如果不是那么我们必须异步处理。wpf中我们可以用<code>dispatcher.checkaccess</code><code>,</code>winform<code>中</code><code>invokerequired</code><code>来检测。并进行相应的操作。</code><code></code>

PostSharp - Thread Dispatching(GUI多线程)

[serializable]

public class onguithreadattribute : methodinterceptionaspect

    public dispatcherpriority priority { get; set; }

    public override void oninvoke(

        methodinterceptionargs eventargs)

        dispatcherobject dispatcherobject =

            (dispatcherobject)eventargs.instance;

        if (dispatcherobject.checkaccess())

        {

            // we are already in the gui thread. proceed.

            eventargs.proceed();

        }

        else

            // invoke the target method synchronously. 

            dispatcherobject.dispatcher.invoke(this.priority, new action(eventargs.proceed));

PostSharp - Thread Dispatching(GUI多线程)

通过上面的两个attribute这下我们可能很简单的操作,gui线程,使得我们并不需要关心实际如何处理更多的时间来关心我们的业务逻辑,从烦躁重复的代码中解脱出来。

静态注入(如postsharp)msbuild+msilinject原理浅析: