C#Threading / Async:在UI可交互的情况下在后台运行任务

时间:2014-01-28 23:37:34

标签: c# wpf multithreading asynchronous

在浏览Async / Await和Threading之后,我仍然不确定将它应用于我的情况的正确方法。无论我尝试我的UI的变化仍然挂起,因为我似乎没有异步调用我想要的函数,另外,我可能实际上需要线程为我的解决方案。

我正在尝试做什么:我有一个WPF应用程序,其中有一个按钮,我想开始一个操作,仍然允许通过UI或其他方式与程序进行交互。一旦满足在此函数之外确定的条件,该函数应该结束。对我来说,这听起来相当标准,但我有一种感觉,我误解了一些东西而且我已经错误地实现了它。

我现在拥有的东西:

private async void start_button_Click(object sender, RoutedEventArgs e)
{
    await StaticClass.MyFunction();
}

private void stop_button_Click(object sender, RoutedEventArgs e)
{
    StaticClass.stopFlag = true;
}

public static Task<int> myFunction()
{
    //Stuff Happens

    while(StaticClass.stopFlag == false)
        //Do Stuff

    //Stuff Happens

    return Task.FromResult(1) //I know this is bad, part of the reason I'm asking
}

我希望得到一些指导,如果我以正确的方式接近这一点,以及对我做错的任何见解。

4 个答案:

答案 0 :(得分:24)

你肯定错误地实现了它。您将返回Task<int>,但只有一旦完成所有工作

在我看来,你应该只有一个同步方法:

private static void MyFunction()
{
    // Loop in here
}

然后像这样开始一个任务:

Task task = Task.Run((Action) MyFunction);

如果你愿意,你可以等待那个任务 - 尽管在你给出的例子中,这样做没有意义,因为你在await之后没有做任何事情。

我也同意里德的看法,使用CancellationToken会比其他地方的静态旗更干净。

答案 1 :(得分:7)

你确实误解了。

public static Task<int> myFunction()
{
    //Stuff Happens

    while(StaticClass.stopFlag == false)
        //Do Stuff

    //Stuff Happens

    return Task.FromResult(1) //I know this is bad, part of the reason I'm asking
}

所有这些代码仍然发生在初始await StaticClass.MyFunction();调用中,它永远不会将控制权返回给调用者。你需要做的是将循环部分放入一个单独的线程中。

public static async Task myFunction()
{
    //Stuff Happens on the original UI thread

    await Task.Run(() => //This code runs on a new thread, control is returned to the caller on the UI thread.
    {
        while(StaticClass.stopFlag == false)
            //Do Stuff
    });

    //Stuff Happens on the original UI thread after the loop exits.
}

答案 2 :(得分:3)

您应该考虑使用框架中内置的managed cancellation framework,而不是尝试使用bool

基本上,您需要构建CancellationTokenSource,并将CancellationToken传递给您的方法,该方法可用于处理取消。

最后,您当前的方法永远不会脱离UI线程。如果您不想阻止UI,则需要使用Task.Run或类似方法将方法移动到ThreadPool。

答案 3 :(得分:1)

作为替代方案,您可以考虑使用BackgroundWorker类来完成工作,您的UI将保持互动。