Async/Await avec un WinForms ProgressBar
J'ai eu ce type de chose, travaillant dans le passé avec un BackgroundWorker, mais je veux profiter de la nouvelle async/await approche de .NET 4.5. J'ai peut-être aboiements le mauvais arbre. Veuillez informer.
Objectif: Créer un composant qui vont faire de longs et afficher un formulaire modal avec une barre de progression comme il fait le travail. Le composant va obtenir le handle d'une fenêtre pour bloquer l'interaction alors que c'est l'exécution de l'œuvre.
Statut: Voir le code ci-dessous. J'ai pensé que j'allais bien jusqu'à ce que j'ai essayé d'interagir avec windows. Si je laisse les choses seul (c'est à dire de ne pas y toucher!), tout fonctionne "parfaitement", mais si je le fais autant que de cliquer sur la fenêtre du programme se bloque au bout de la longue course de travail se termine. Réelles interactions (glisser) sont ignorées, comme si le thread d'INTERFACE utilisateur est bloqué.
Questions: Puis mon code fixe assez facilement? Si oui, comment? Ou, devrais-je utiliser une approche différente (par exemple, BackgroundWorker)?
Code (Form1 est un formulaire standard avec une ProgressBar et une méthode publique, UpdateProgress, qui définit le composant ProgressBar en Valeur):
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting..");
var mgr = new Manager();
mgr.GoAsync();
Console.WriteLine("..Ended");
Console.ReadKey();
}
}
class Manager
{
private static Form1 _progressForm;
public async void GoAsync()
{
var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm = new Form1();
_progressForm.Show(owner);
await Go();
_progressForm.Hide();
}
private async Task<bool> Go()
{
var job = new LongJob();
job.OnProgress += job_OnProgress;
job.Spin();
return true;
}
void job_OnProgress(int percent)
{
_progressForm.UpdateProgress(percent);
}
}
class LongJob
{
public event Progressed OnProgress;
public delegate void Progressed(int percent);
public void Spin()
{
for (var i = 1; i <= 100; i++)
{
Thread.Sleep(25);
if (OnProgress != null)
{
OnProgress(i);
}
}
}
}
class Win32Window : IWin32Window
{
private readonly IntPtr _hwnd;
public Win32Window(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get
{
return _hwnd;
}
}
}
}
Vous devez vous connecter pour publier un commentaire.
@StephenCleary réponse est bonne. Cependant, j'ai dû faire un peu de modification à sa réponse pour obtenir le comportement que je pense que l'OP veut.
La
async
etawait
mots-clés ne signifie pas "exécuter sur un thread d'arrière-plan." J'ai unasync
/attendre
intro sur mon blog qui décrit ce qu'ils ne veux dire. Vous devez explicitement lieu le CPU opérations sur un thread d'arrière-plan, par exemple,Task.Run
.Aussi, le Basée sur les tâches du Modèle Asynchrone documentation décrit les approches communes avec
async
code, par exemple, les rapports sur les progrès.Noter que le
Progress<T>
type gère correctement fil marshaling, donc il n'y a pas besoin de marshaling dansForm1.UpdateProgress
.Console
, il n'est pasSynchronizationContext
. Je pense qu'il doit être mis en place pourProgress<T>
de travailler correctement?WinFormsSynchronizationContext
lorsqu'ils sont créés, etProgress<T>
ne nécessite pas deSynchronizationContext
(bien qu'il ne vaut mieux travailler avec une).Progress<T>
- ce n'est jamais hit - INTERFACE utilisateur se bloque bien que le travail, c'est de filer. J'ai penséApplication.Run()
était nécessaire pour établirSynchronizationContext
- ne_progressForm.Show
établissement? Je ne suis pas sûr.SynchronizationContext
mais pas de la boucle principale.Main
il faudrait appelerApplication.Run
,ShowDialog
, ou quelque chose comme ça.SynchronizationContext
est-il - mais pas de boucle pour traiter les chosesPosted/Send
à elle. D'où mon point de rupture de l'habitude de frapper. Merci.Corrigez-moi si je me trompe, mais cela semble être la façon la plus simple de mettre à jour une barre de progression.