Compact Framework/Threading - MessageBox s'affiche sur les autres contrôles une fois l'option choisie

StackOverflow https://stackoverflow.com/questions/10071

Question

Je travaille sur une application qui récupère et installe un tas de mises à jour sur un serveur externe et j'ai besoin d'aide pour le threading.L'utilisateur suit ce processus :

  • Bouton clics
  • La méthode vérifie les mises à jour, le nombre est renvoyé.
  • S'il est supérieur à 0, demandez à l'utilisateur s'il souhaite installer à l'aide de MessageBox.Show().
  • Si oui, il parcourt une boucle et appelle BeginInvoke() sur la méthode run() de chaque mise à jour pour l'exécuter en arrière-plan.
  • Ma classe de mise à jour contient des événements utilisés pour mettre à jour une barre de progression, etc.

Les mises à jour de la barre de progression sont correctes, mais la MessageBox n'est pas complètement effacée de l'écran car la boucle de mise à jour démarre juste après que l'utilisateur clique sur oui (voir capture d'écran ci-dessous).

  • Que dois-je faire pour que la boîte de message disparaisse instantanément avant le début de la boucle de mise à jour ?
  • Dois-je utiliser Threads au lieu de BeginInvoke() ?
  • Dois-je effectuer la vérification initiale de la mise à jour sur un thread séparé et appeler MessageBox.Show() à partir de ce thread ?

Code

// Button clicked event handler code...
DialogResult dlgRes = MessageBox.Show(
    string.Format("There are {0} updates available.\n\nInstall these now?", 
    um2.Updates.Count), "Updates Available", 
    MessageBoxButtons.YesNo, 
    MessageBoxIcon.Question, 
    MessageBoxDefaultButton.Button2
);

if (dlgRes == DialogResult.Yes)
{
    ProcessAllUpdates(um2); 
}

// Processes a bunch of items in a loop
private void ProcessAllUpdates(UpdateManager2 um2)
{
    for (int i = 0; i < um2.Updates.Count; i++)
    {
        Update2 update = um2.Updates[i];

        ProcessSingleUpdate(update);

        int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count);

        UpdateOverallProgress(percentComplete);
    }
}

// Process a single update with IAsyncResult
private void ProcessSingleUpdate(Update2 update)
{
    update.Action.OnStart += Action_OnStart;
    update.Action.OnProgress += Action_OnProgress;
    update.Action.OnCompletion += Action_OnCompletion;

    //synchronous
    //update.Action.Run();

    // async
    IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); });
}

Capture d'écran

Windows Mobile Bug

Était-ce utile?

La solution

Votre interface utilisateur n'est pas mise à jour car tout le travail se déroule dans le fil de l'interface utilisateur.Votre appel à :

this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 

dit d'invoquer update.Action.Run() sur le thread qui a créé "ceci" (votre formulaire), qui est le thread de l'interface utilisateur.

Application.DoEvents()

donnera en effet au fil de l'interface utilisateur la possibilité de redessiner l'écran, mais je serais tenté de créer un nouveau délégué et d'appeler BeginInvoke à ce sujet.

Cela exécutera la fonction update.Action.Run() sur un thread séparé alloué à partir du pool de threads.Vous pouvez ensuite continuer à vérifier IAsyncResult jusqu'à ce que la mise à jour soit terminée, en interrogeant l'objet de mise à jour pour connaître sa progression après chaque vérification (car vous ne pouvez pas demander à l'autre thread de mettre à jour la barre de progression/l'interface utilisateur), puis en appelant Application.DoEvents().

Vous êtes également censé appeler EndInvoke() par la suite, sinon vous risquez de perdre des ressources.

Je serais également tenté de mettre un bouton d'annulation sur la boîte de dialogue de progression et d'ajouter un délai d'attente, sinon si la mise à jour reste bloquée (ou prend trop de temps), votre application sera verrouillée pour toujours.

Autres conseils

As-tu essayé de mettre un

Application.DoEvents()

ici

if (dlgRes == DialogResult.Yes)
{
   Application.DoEvents(); 
   ProcessAllUpdates(um2); 
}

@John Sably

Vous pouvez vous en sortir pas appeler EndInvoke lorsqu'il s'agit de WinForms sans aucune conséquence négative.

La seule exception documentée à la règle que je connaisse se trouve dans Windows Forms, où vous êtes officiellement autorisé à appeler Control.BeginInvoke sans prendre la peine d'appeler Control.EndInvoke.

Cependant, dans tous les autres cas, lorsque vous traitez le modèle Begin/End Async, vous devez supposer qu'il fuira, comme vous l'avez indiqué.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top