C# - VS2010:如何做一些事情并等待一段时间而不阻止UI?

时间:2014-08-14 20:36:09

标签: c# visual-studio-2010

我正在制作一个简单的应用程序,我需要做一些事情,并更新进度条。我做了一些事情,等待1秒,如果执行没问题,我会增加进度条,做一些其他的事情,再等一下,如果确定,增加进度条,依此类推,7次。通过东西,这意味着我通过RS232连接到电子板,发送一些命令,然后执行,1秒钟后我检查电路板上是否一切正常。我需要等待1秒才能获得电路板上的一些模拟内容。

问题在于等待一秒钟。如果我使用Thread.Sleep(1000),整个用户界面会冻结(如预期的那样)并且进度条在“未同步”中工作,等待同样的原因。

我的代码就像:

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秒钟?

Thanx任何帮助!!!

2 个答案:

答案 0 :(得分:1)

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

从概念上讲,您应该创建一个 new 线程来连接RS232板。您的主线程(UI线程)继续执行,不会冻结UI。如果这是一个Windows应用程序,您应该阅读有关多线程编程的更多信息,因为在Windows应用程序中使用单个线程需要“同时”执行许多操作,这将始终导致阻塞和冻结问题。

如果您的.NET Framework版本不支持TPL,那么您应该使用名为BackgroundWorker的类。这是一个让您入门的小例子:http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx

PS:我的回答是基于您正在编写Windows窗体应用程序的假设。

答案 1 :(得分:1)

这是一个非常简单,人为的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调用该任务。