3

I know that the question may not make sense, and I'm having a tough time trying to think of a way to explain it, so I will show a snippet of code to help. I'm using Winforms on visual studio express 2010:

private void button1(object sender, EventArgs e)
    {
        txtOutput.Text += "Auto-collecting variables. This may take several minutes";
        string v = foo();
        txtOutput.Text += "\n" + v;
        string b = bar();
        txtOutput.Text += "\n" + b;

        txtOutput.SelectionStart = txtOutput.Text.Length;
        txtOutput.ScrollToCaret(); //scrolls to the bottom of textbox
    }

So basically, when the user clicks button1, I want "Auto-collecting variables..." to be displayed in the textbox, and then have foo() execute, display that, and then have bar() execute, and then display that.

What is currently happening is that foo() and bar() execute, and then everything is displayed all at once after foo() and bar() have executed (functions that take several minutes). Is there anyway to fix this, or is there a work around?

Edit: Version of C# is 4.0. If I update to 4.5 or 5.0, will computers without .NET 4.5/5.0 be able to run the .exe?

4

5 回答 5

6

C# 5.0 使这样做变得微不足道。

使用在后台线程中执行长时间运行的任务,Task.Run并使用await作为 UI 线程中的延续执行该方法的其余部分,而不会在异步任务期间阻塞 UI 线程。

private async void button1(object sender, EventArgs e)
{
    txtOutput.Text += "Auto-collecting variables. This may take several minutes";
    string v = await Task.Run(() => foo());
    txtOutput.Text += "\n" + v;
    string b = await Task.Run(() => bar());
    txtOutput.Text += "\n" + b;

    txtOutput.SelectionStart = txtOutput.Text.Length;
    txtOutput.ScrollToCaret(); //scrolls to the bottom of textbox
}

您可以在 C# 4.0 中这样做:(第一个解决方案将由编译器转换为类似的东西。)

private  void button1(object sender, EventArgs e)
{
    txtOutput.Text += "Auto-collecting variables. This may take several minutes";
    Task.Factory.StartNew(() => foo())
        .ContinueWith(t => txtOutput.Text += "\n" + t.Result
            , TaskScheduler.FromCurrentSynchronizationContext())
        .ContinueWith(t => bar())
        .ContinueWith(t =>
        {
            txtOutput.Text += "\n" + t.Result;
            txtOutput.SelectionStart = txtOutput.Text.Length;
            txtOutput.ScrollToCaret(); //scrolls to the bottom of textbox
        }
            , TaskScheduler.FromCurrentSynchronizationContext());
}
于 2013-06-12T15:37:22.437 回答
2

根据 .NET 的版本,您可以使用BackgroundWorker (Pre 4.0) 或Tasks (Post 4.0 - 3.5 with an add-on)...仅举几例。

后台工作人员伪代码:

var backgroundWorker = new BackgroundWorker()

method
{
    //Update UI
    backgroundWorker.RunWorkAsync()
}

asyncworkmethod
{
    //do main logic
}

asynccompletemethod
{
    //Update UI to say done
}

任务伪代码:

method
{
     //Update UI
     TaskFactory.StartNew(()=>DoWork).ContinueWith((previousTask)=>UpdateUIToSayDone)
}

而且,如果您使用的是 4.5,那么您可以使用async/await关键字,但这只是围绕任务的语法糖(主要是......)。Servy 已经有一个很好的例子,不过如果你采用这种方法

于 2013-06-12T15:32:58.250 回答
2

使用BackgroundWorker该类在不阻止 UI 更新的情况下进行处理。它具有可用于将进度信息传输到 UI 线程的事件。

于 2013-06-12T15:33:12.650 回答
0

使用后台进程(阅读其他答案)是正确的方法,但如果您正在寻找一个非常快速的解决方法,您可以Application.DoEvents()在更新 TextBox 后调用。在大多数情况下,此调用将导致您的表单更新以反映您所做的更改。

于 2013-06-12T15:36:50.317 回答
0

txtOutput.Update()应该做你想做的,但你应该考虑使用后台线程来完成长时间运行的任务而不阻塞 UI 线程。

于 2013-06-12T15:38:26.473 回答