zoukankan      html  css  js  c++  java
  • 浅析.Net 在 winform及wpf中涉及界面交互的多线程类的封装

    我们在开发客户端程序时,经常要用到多线程

    而我们知道 .Net 中从线程安全的考虑,对控件改变的调用要通过Invoke beginvoke 来进行,这就涉及怎么进行工作线程与界面的互操作。

    本文以一个简单的应用为例,探讨多线程的封装性,我们的主要目的是让一个类能同时适wpfwinform对多线程的要求

    现在假定程序里,有一个多线程的业务处理逻辑,如下:

    //……初始化等
    Thread work = new Thread(new ThreadStart(run));
    work.Start();
    //……其他代码

    void run (){

    //这里有一部分要改变界面显示的代码

     

    在最直观的设计中,我们是这样考虑的:

    1.声明一个委托(为了从简,这里不考虑有各种参数的情况:

    private void foo();

    2.将用户界面交互的代码装在一个单独的函数中:

    private void Foo(){
    //改变界面显示
    }

    3.在线程中(这里先以winform为例) InvokeBeginInvoke调用 这个函数

    为了从简,我们只考虑Invoke

     

    void run(){
    //….
    this.Invoke(new foo(Foo));
    //….
    }

    现在,我们的下一步工作是要封装这个Work类,使他在其他的winform程序中也可以方便的调用。这样,我们主要有两部分工作要做:

     a.工作线程的提取

     b.界面逻辑的分割

    最直接的方法是这样:

    delegate void foo();
    class Work{
     
    private Thread work;
    public Work(){
    work= new Thread(new ThreadStart(run);
    }
    public Begin(){
    work.Start();
    }

    public event foo Foo;

    void run (){

    //这里有一部分要改变界面显示的代码
    if(Foo!=null)
        Foo();


    }

      

    这样,界面上的代码变成了这个样子:

    //初始化
    Work = new Work(this);
    Work.Foo+= new foo(FooFunction);
    Work.Begin()

    到此,我们已经将多线程逻辑与界面逻辑分开了,但是现在有一个问题,就是我 要在FooFuction中调用Invoke

     

    FooFuction(){
    this.Invoke(new Foo(fooFunction));
    }
    fooFunction(){
    //界面处理程序
    }

    于是,每次复用这个逻辑,我们都要反复的自己写这个Invoke ,很麻烦,于是考虑进一步的改进,即,将当前Control作为一个成员封装至Work类中,即:

     

    delegate void foo();
    class Work{
     private Control Owner ;
    private Thread work;
    public Work(Control owner){
    work= new Thread(new ThreadStart(run);
    Owner=owner;
    }
    public Begin(){
    work.Start();
    }

    public event foo Foo;

    void run (){

    //这里有一部分要改变界面显示的代码
    if(Foo!=null)
        if(Ownner!=null)
            Ownner.Invoke(Foo);
        else 
            Foo();

    }

    这样,界面 上的代码就要整洁多了,现在我们不用在界面中调用 Invoke了:

     

    //初始化
    Work = new Work();
    Work.Foo+= new foo(FooFunction);
    Work.Begin()

    //other code ...
     FooFuction(){
    //更新界面 
    }

    现在,我们已经完成了一个多线程类的封闭,它有很好的封闭性和可读性,但是,新的问题来了,即,我要把它移植到 wpf程序中,本来很完美的工作类,现在他面临如下问题:

    1.不与wpf程序兼容,我得自己在程序中写对应wpfInvoke

    2.运行时要依靠Control类,即我要正常使用他,还得在wpf程序中添加winformDLL才可以

    因此,我们要进行如下工作,以使我们的Work类看着很完美

    1.脱离Control类的依赖

    2.能同时完美的支持winform wpf用户程序;

    显然,这里面最重要的就是要如何处理这段代码 :

    //这里有一部分要改变界面显示的代码
    if(Foo!=null)
        if(Ownner!=null)
            Ownner.Invoke(Foo);
        else 
            Foo();

    考虑到我们对Control的引用 只是为了调用它的Invoke ,于是,可以将Invoke提一个接口

    interface  IWorkHost{
    void Invoke (delegate method);
    public object Parent;
    }

    这样,我们只需将Work类中的Owner Control变为IWorkHost,其他代码不用改变,剩下的工作就好办了:

    我们可以把对windows.forms 引用从Work所在的工程移掉,然后,加一个DLL工程WinformHost ,引用 Work类所在工程

    声明一个类WinformHost来实现IWorkHost

    class WinformHost:IWorkHost{
    private Control parent;
    public object Parent{get{return parent;}}
    public WinformHost(Control parent){
    parent = parent;
    }
    public void Invoke (delegate method){
    parent.Invoke(method);
    }

    类似的,增加用于WPF的WPFWorkHost

    class WPFHost:IWorkHost{
    private Dispatcher parent;
    public object Parent{get{return parent;}}
    public WPFHost(Control parent){
    parent = parent;
    }
    public void Invoke (delegate method){
    parent.Invoke(method);
    }

    这样,当在winform中使用Work类时,代码变成:

    Work = new Work(new WinformHost(this));
    Work.Foo+= new foo(FooFunction);
    Work.Begin()

    当在 wpf程序中使用 work类时,代码变成:

     

    Work = new Work(new WPFHost(this.dispatcher));
    Work.Foo+= new foo(FooFunction);
    Work.Begin()

    总结:

    我们在这个文章里依次做了如下的工作:

    1.将一个多线程的逻辑加到winform中

    2.将这个多线程封装到单独的类

    3.改进这个逻辑使他同时适应winform和wpf

    这里用到到模式,应该是适配器模式,其实这个应用场景和很多复用封装的场景相类似,只不过多线程在 winform和wpf中是经常讨论的问题,用这个问题来解释这种封装,我觉得会好一些。

    文笔不好,见谅。

  • 相关阅读:
    C++如何在Dialog和View中显示梯度背景颜色
    C++MFC的关键类(View,Application,Frame,Document等等)之间访问方法列表
    C++深入分析MFC文档视图结构(项目实践)
    C++如何修改SDI程序的默认背景颜色
    BAPI使用HR_INFOTYPE_OPERATION函数批量导入HR信息纪录代码样例(0759信息类型)
    C++在单文档的应用程序增加多个视图
    SD定价过程的16个字段的作用说明
    HR上载信息类型的长文本的样例代码
    C++在工具条中加入组合框控件
    C++如何锁定splitter窗口
  • 原文地址:https://www.cnblogs.com/geyunfei/p/2244980.html
Copyright © 2011-2022 走看看