zoukankan      html  css  js  c++  java
  • C#桌面应用使用异步计算改善界面效果的两种方式

    在桌面应用中,我们希望当一个费时的运算在进行的时候,当前窗体可以有所表现,比如显示等待动画或者进度条,避免让用户陷入无聊、乏味又不知何时才能执行完成的苦闷之中,此时异步计算即可派上用场,所谓异步,即是将费时的运算放到一个专门的工作线程里面去,不在当前UI线程里面处理,如果在UI线程内处理,UI势必会进入假死状态,期间用户无法移动窗体,无法取消费时操作,只能等待程序处理完毕,程序的控制权才会重新交换给用户,这种方式前面也说了,相当的不友好!其实这里的异步操作类似于WEB开发中常用的AJAX,调用XMLHTTP在后台操作,等操作完成后调用回调函数,给用户结果,控制权一直都在用户手里,感觉肯定不一样。:)

    好了,说了使用和不用异步运算的区别,我们下边说说在.NET中,使用C#语言,实现异步操作的两种方式:

    一,使用delegate代理

    1、假如需要在工作线程进行长时间工作的方法是:int StartExportData()

    //导出旧库
    public int StartExportData()
    {
        
    return new ExportData().StartExportDataToTmp();
    }

    2、定义上述方法的委托方法

    //StartExportData方法委托,异步调用StartExportData方法,避免主线程阻塞。
    delegate int StartExportDataDelegate();

    3、定义回调方法,指示当StartExportData()执行完成后所进行的操作

    //回调方法,当StartExportData方法执行完毕返回后执行的回调。
    public void ExportCallBackMethod(System.IAsyncResult exportResult)
    {
        
    //获得委托对象
        StartExportDataDelegate d1 = (StartExportDataDelegate)exportResult.AsyncState;
        
    //EndInvoke方法必须调用,取得被委托方法的返回值
        int result = d1.EndInvoke(exportResult);
        
    if (result == 1)    //如果返回为1,表示外部程序成功返回
        {
            ShowMessage(
    "成功导出旧年度数据库 ...");    //更新信息提示

        }
        d1 
    = null;
    }

    4、在新的工作线程内启动被代理的方法

    //初始化委托方法对象
    StartExportDataDelegate d1 = new StartExportDataDelegate(StartExportData);
    //初始化回调方法对象
    System.AsyncCallback c1 = new System.AsyncCallback(ExportCallBackMethod);
    //使用BeginInvoke方法启动异步线程,在线程内执行被委托方法StartExportData,
    //线程执行完毕后调用回调方法CallBackMethod
    d1.BeginInvoke(c1, d1);

    5、最后,要说明的是,需要引入Threading:

    using System.Threading;

    二、使用BackgroundWorker 类,它是在 .NET Framework 2.0 版中是新增的。

    还是对上述方法的异步调用,换用BackgroundWorker后会是怎样的呢?我们一起来看一下:

    1、初始化类的两个事件:DoWork和RunWorkerCompleted,顾名思义,DoWork即为工作线程,在该方法内调用工作方法; RunWorkerCompleted即为回调方法,即为工作方法完成后所调用的方法。这里的bgWorker为BackgroundWorker类的实例。

    /// <summary>
    /// 初始化工作线程事件处理程序
    /// </summary>
    private void initBackgroundWorker()
    {
        bgWorker.DoWork 
    += new DoWorkEventHandler(bgWorker_DoWork);
        bgWorker.RunWorkerCompleted 
    += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
    }

    2、在类的构造函数内调用上述初始化方法。

    public BaseDataForm()
    {
        InitializeComponent();
        initBackgroundWorker();
    }

    3、修改方法的签名,增加两个参数。

    private int StartExportData(BackgroundWorker worker, DoWorkEventArgs e)
    {
        
    try
        {
            ... ...
        }
        
    finally
        {

        }
        
    return 0;
    }

    4、实现DoWork方法。

    /// <summary>
    /// 工作线程所做工作
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker 
    = sender as BackgroundWorker;
        e.Result 
    = process(worker, e);
        
    //以下为接受多个参数的方法,一个参数就不用说了吧 :)
       
    //string arg1 = ((ArrayList)e.Argument)[0].ToString();
        
    //string arg2 = ((ArrayList)e.Argument)[1].ToString();
        
    //e.Result = compare(arg1, arg2 , worker, e);
    }

    5、实现RunWorkerCompleted方法。

    /// <summary>
    /// 工作线程结束后所做工作
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        
    if (e.Error != null)
        {
            ShowMessage(ResUtils.getString((
    "TaskError")));
            btnStart.Enabled 
    = true;
            btnClose.Enabled 
    = true;
            picBox.Enabled 
    = false;
            MessageBox.Show(e.Error.Message, SystemContext.APP_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
            
    if (log.IsErrorEnabled)
            {
                log.Error(e.Error.Message, e.Error);
            }
        }
        
    else
        {
            ShowMessage(ResUtils.getString((
    "TaskSuccess")));
            btnStart.Enabled 
    = true;
            btnClose.Enabled 
    = true;
            picBox.Enabled 
    = false;
        }
    }

    6、启动后台工作线程。

    private void btnStart_Click(object sender, EventArgs e)
    {
        
    if (check())
        {
            btnStart.Enabled 
    = false;
            btnClose.Enabled 
    = false;
            bgWorker.RunWorkerAsync();
    //这里可以添加一个参数对象,如果单个参数直接传,如果多个参数封装到类或ArrayList

        
    //以下为传送多个参数的方法,一个参数就不用说了吧 :)
        
    //ArrayList arg = new ArrayList(2);
        
    //arg.Add(txtExcelFile.Text);
        
    //arg.Add(cmbReportType.Text);
        
    //bgWorker.RunWorkerAsync(arg); //晕啊,传多个参数竟然非要用数组或者对象
        }
    }

    7、最后,同样,要引入的类为:

    using System.Threading;

    事实上,没有什么要比发现、培养、呵护、调整自己的心智的力量更重要的事情了.........

  • 相关阅读:
    Linux内核网络协议栈优化总纲
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 链表数据求和操作
  • 原文地址:https://www.cnblogs.com/appleseed/p/1331830.html
Copyright © 2011-2022 走看看