C # Threading / Async: Executar uma tarefa em segundo plano enquanto a interface do usuário é interativa

Depois de olhar em ambos os Async / Await e Threading, eu ainda não tenho certeza do caminho certo para aplicá-lo à minha situação. Não importa a variação que eu tentei a minha interface do usuário ainda trava porque eu não parecem estar chamando a minha function desejada de forma assíncrona, além disso, na verdade eu posso precisar de threading para a minha solução.

O que eu estou tentando fazer: Eu tenho um aplicativo WPF no qual há um botão que eu gostaria de iniciar uma operação que ainda permite a interação com o programa, através da interface do usuário ou não. Quando uma condição é atendida e determinada fora dessa function, a function deve terminar. Para mim, isso parece bastante normal, mas tenho a sensação de que estou entendendo mal uma coisa e a implementei incorretamente.

O que eu tenho agora:

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 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 } 

Eu estava esperando por alguma orientação sobre se estou me aproximando disso da maneira certa e qualquer insight sobre o que estou fazendo de errado.

Você definitivamente o implementou incorretamente. Você está retornando uma Task , mas somente uma vez que todo o trabalho já foi feito .

Parece-me que você provavelmente deveria ter apenas um método síncrono :

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

Então inicie uma tarefa para isto assim:

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

Você pode então esperar essa tarefa se quiser – embora no exemplo que você deu, não há sentido em fazê-lo, já que você não está fazendo nada depois da await .

Eu também concordaria com Reed que usar um CancellationToken seria mais limpo do que um sinalizador estático em outro lugar.

Você entendeu mal.

 public static Task 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 } 

Todo esse código ainda acontece no await StaticClass.MyFunction(); chamada, nunca devolve o controle ao chamador. O que você precisa fazer é colocar a parte do loop em um thread separado.

 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. } 

Em vez de tentar usar um bool para isso, você deve considerar o uso da estrutura de cancelamento gerenciada incorporada ao framework.

Basicamente, você criaria um CancellationTokenSource e passaria um CancellationToken ao seu método, que poderia ser usado para manipular o cancelamento.

Finalmente, seu método atual nunca sairá do thread da interface do usuário. Você precisaria usar Task.Run ou similar para mover o método para o ThreadPool se não quiser bloquear a interface do usuário.

Como alternativa, você poderia procurar usar a class BackgroundWorker para fazer o trabalho, sua interface do usuário permanecerá interativa.