UI界面多线程简单实现

        这些天给我们公司一个七八年的软件进行功能扩展,最大的感觉就是数据量大时界面特卡。打包安装后,运行起来就一直关不掉,得运行完毕才能关,运行时就是用任务管理器关都关不掉。于是想起了一个问题:Winform如何解决界面假死。

        一直以来我只知道可以直接用Application.DoEvent()实现。其他的也就想想,估计多线程可以实现,但一直也没去研究。我构思的效果:现在界面在干一件事(正在进行中),忽然想起来要干另一件事(同时运行)。这种效果当前在winform上是不行的,界面会卡住且不接受任何操作。为实现这个效果,准备写个例子实现两个按钮分别批量更新两个文本框中的内容,并且更新的值能够及时反馈到UI上,最先应用Application.DoEvent()实现。主要代码如下:

private void btnUpdate_Click(object sender, EventArgs e)
{
    btnUpdate.Enabled = false;
    for (int i = 30000; i > 0; i--)
    {
        tbValue.Text = i.ToString();
        Application.DoEvents();
    }
    btnUpdate.Enabled = true;
}
private void btnOther_Click(object sender, EventArgs e)
{
    btnOther.Enabled = false;
    for (int i = 30000; i > 0; i--)
    {
        tbOther.Text = i.ToString();
        Application.DoEvents();
    }
    btnOther.Enabled = true;
}

        代码说明:btnUpdate按钮可以更新tbValue文本框的值,btnOther按钮可以更新tbOther文本框的值。

        结果发现会卡住其中一个,等另一个完成之后才继续完成,不是我想要的效果。于是乎只能运用多线程(仅限我知道的,其他应该有方法实现),找了找说用invoke方法。

private void btnUpdate_Click(object sender, EventArgs e)
{
    // ThreadStart委托,它表示此线程开始执行时要调用的 方法。详细了解参照MSDN
    Thread thread = new Thread(new ThreadStart(this.ThreadUpdateValue1));
    thread.Start();
}
private void ThreadUpdateValue1()
{
    btnUpdate.Enabled = false;
    for (int i = 30000; i > 0; i--)
    {
        this.Invoke(new Action<int>(this.UpdatetbValue1), i);
    }
    btnUpdate.Enabled = true;
}
private void UpdatetbValue1(int value)
{
        tbValue.Text = value.ToString();
}
private void btnOther_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(this.ThreadUpdateValue2));
    thread.Start();
}
private void ThreadUpdateValue2()
{
    btnOther.Enabled = false;
    for (int i = 30000; i > 0; i--)
    {
        this.Invoke(new Action<int>(this.UpdatetbValue2), i);
    }
    btnOther.Enabled = true;
}
private void UpdatetbValue2(int value)
{
        tbOther.Text = value.ToString();
}

        注:关于Action可以参考msdn   http://msdn.microsoft.com/zh-cn/library/018hxwa8.aspx

        发现报出错误:

UI界面多线程简单实现_第1张图片

        还好百度无所不在,搜到这篇博客。只要设置Control.CheckForIllegalCrossThreadCalls = false;就可以了。测试发现还不如Application.DoEvents();的效果,直接卡掉直至全部完成才恢复,好歹用Application.DoEvents()还能看到是先后运行的。分析原因,窗体类被锁住了,Application.DoEvents()在计算和更新界面之间能够自动调度,而线程不能够自动调度。想起几天前看的一博客上说[MethodImpl(MethodImplOptions.Synchronized)]加在方法上时锁定对象,加在静态方法上时只锁定方法。于是乎将this.invoke改成tbValue.Invoke(new Action<int>(this.UpdatetbValue1), i);这样就只锁住该控件而不是锁住全部界面,测试一下效果发现,还不错,基本上能够感觉到同时在运行(只是视觉上哦)。至此以为大功告成,想到我现在的软件在运行时关不掉,那么这个在运行时关闭会怎样呢?一测,有收获,报错了:

UI界面多线程简单实现_第2张图片

        错误提示说的很明确,另一个线程中去操作这个被关掉的窗口了。怎么处理呢?在线程中判断IsDisposed发现也确实为true,但就是不能中断,而是报错。在测试时还发现在点击事件中用try catch是捕捉不到新线程上的错误的。暂且在执行代码区域加上Try Catch可以解决,再找原因,看到百度空间上一博客,发现用Environment.Exit(0);才可以彻底退出。为了不添加复杂度,项目中计时的精确度只到秒,大概看到效果就行。

        后记:写出来才有些意想不到的收获,比如异常部分,以前我对异常的认识一直认为只要在高层捕获异常就可以了,在单线程中可以,但今天才发现多线程中不可以(以前也没想过这个问题,对多线程基本上还只是处于认识阶段,写过例子,没用过)。有些东西平时不多去想一想,试一试,认识就不会提高。当然了,本人认识还处于初级阶段,还望路过的大牛们不吝指教。

        项目源代码(还有项目中提到的一个异常的例子)。

 

你可能感兴趣的:(多线程,WinForm,界面假死)