c# - VS2010:如何在不阻塞UI的情况下做一些事情并等待一段时间

本文关键字:情况下 一段时间 等待 UI VS2010 | 更新日期: 2023-09-27 18:18:08

我正在制作一个简单的应用程序,我需要做一些事情,并更新进度条。我做一些事情,等待1秒,如果执行成功,我增加进度条,做一些其他事情,再等一秒,如果成功,增加进度条,以此类推,7次。通过东西,这意味着我通过RS232连接到电子板,发送一些命令,它执行,1秒后我检查板上是否一切正常。我需要在黑板上等待一些类似的东西。

问题在于等待那一秒钟。如果我使用Thread.Sleep(1000),整个UI冻结(如预期的那样),并且进度条以"未同步"的方式等待相同的原因。

我的代码是:

progressBar1.Value = 0;
/* Do some stuff */
Thread.Sleep(1000);
/* Check the stuff */
progressBar1.Value = 1;
/* Do some stuff */
Thread.Sleep(1000);
/* Check the stuff */
progressBar1.Value = 2;
/* Do some stuff */
Thread.Sleep(1000);
/* Check the stuff */

等等…7次。

每一步的"东西"都不一样。

让我的代码等待1秒的最好方法是什么?

谢谢你的帮助!

c# - VS2010:如何在不阻塞UI的情况下做一些事情并等待一段时间

你应该使用任务并行库(TPL),如果你的。net框架版本支持它。这正是TPL设计要解决的问题。为此,您将启动一个异步Task,它是在Thread类之上的封装。

从概念上讲,您应该为连接到RS232板创建一个新的线程。你的主线程(UI线程)继续执行,不会冻结UI。如果这是一个Windows应用程序,你应该阅读更多关于多线程编程的知识,因为在需要"一次"做很多事情的Windows应用程序中使用单个线程总是会导致阻塞和冻结问题。

如果你的。net框架版本不支持TPL,那么你应该使用一个叫做BackgroundWorker的类。下面是一个小示例:http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx

PS:我的答案是基于你正在编程一个Windows窗体应用程序的假设。

这是一个非常简单的,人为的WinForms示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
namespace ProgressBar
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void btnDoWork_Click(object sender, EventArgs e)
        {
            Task task1 = new Task(() => { System.Threading.Thread.Sleep(5000); });
            Task task2 = new Task(() => { System.Threading.Thread.Sleep(5000); });
            Task task3 = new Task(() => { System.Threading.Thread.Sleep(5000); });
            Task task4 = new Task(() => { System.Threading.Thread.Sleep(5000); });
            task1.ContinueWith((t) =>
            {
                if (t.Exception != null)
                    t.Exception.Handle(ex =>
                    {
                        //do something
                        return true;
                    });
                progressBar.Value = 25;
            }, TaskScheduler.FromCurrentSynchronizationContext()).ContinueWith((t) => task2.Start());

            task2.ContinueWith((t) =>
            {
                if (t.Exception != null)
                    t.Exception.Handle(ex =>
                    {
                        //do something
                        return true;
                    });
                progressBar.Value = 50;
            }, TaskScheduler.FromCurrentSynchronizationContext()).ContinueWith((t) => task3.Start());
            task3.ContinueWith((t) =>
            {
                if (t.Exception != null)
                    t.Exception.Handle(ex =>
                    {
                        //do something
                        return true;
                    });
                progressBar.Value = 75;
            }, TaskScheduler.FromCurrentSynchronizationContext()).ContinueWith((t) => task4.Start());
            task4.ContinueWith((t) =>
            {
                if (t.Exception != null)
                    t.Exception.Handle(ex =>
                    {
                        //do something
                        return true;
                    });
                progressBar.Value = 100;
            }, TaskScheduler.FromCurrentSynchronizationContext());
            task1.Start();
        }
    }
}

基本上,只需为每个操作创建一个任务;然后在继续执行该任务时,检查AggregateException(这非常重要,因为如果不检查它并且出现异常,则在任务被垃圾收集时程序将崩溃)。在完成该延续后,只需启动下一个任务。如果您需要从其中一个任务执行UI访问,请确保从CurrentSynchronizationContext调用该任务。