Question

C # 2008

J'utilise le code ci-dessous pour me connecter à un logiciel de téléphonie. Cependant, le processus de connexion est un processus long, car de nombreuses choses doivent être initialisées et vérifiées. Je n’en ai mis que quelques-unes ici, car cela rendrait le code trop long pour pouvoir être publié.

Dans le code ci-dessous, je vérifie si AnnulationPendante si l'événement CancelAsync a été appelé lors de mon clic sur le bouton d'annulation, avant chaque vérification. Est-ce correct? De plus, si la vérification échoue, j'appelle aussi CancelAsync et définit e.Cancel sur true.

Je voudrais savoir si ma méthode que j'ai utilisée ici est la meilleure méthode à utiliser.

Merci beaucoup pour vos conseils,

private void bgwProcessLogin_DoWork(object sender, DoWorkEventArgs e)
    {   
        /*
         * Perform at test to see if the background worker has been
         * cancelled by the user before attemping to continue to login.
         * 
         * Cancel background worker on any failed attemp to login
         */

        // Start with cancel being false as to reset this if cancel has been set to true
        // in the cancel button.
        e.Cancel = false;

        NetworkingTest connection_test = new NetworkingTest();
        if (!this.bgwProcessLogin.CancellationPending)
        { 
            // Check local LAN or Wireless connection               
            if (!connection_test.IsNetworkConnected())
            {
                // Update label
                if (this.lblRegistering.InvokeRequired)
                {
                    this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(UpdateRegisterLabel), "No network connection");
                }
                else
                {
                    this.lblRegistering.Text = "No network connection";
                }
                // Failed attemp
                this.bgwProcessLogin.CancelAsync();
                e.Cancel = true;
                return;
            }
            // Report current progress
            this.bgwProcessLogin.ReportProgress(0, "Network connected");
        }
        else
        {
            // User cancelled 
            e.Cancel = true;
            return;
        }

        // Test if access to Server is available
        if (!this.bgwProcessLogin.CancellationPending)
        {
            if (!connection_test.IsSIPServerAvailable())
            {
                // Update label
                if (this.lblRegistering.InvokeRequired)
                {
                    this.lblRegistering.Invoke(new UpdateRegisterLabelDelegate(UpdateRegisterLabel), "Server unavailable");
                }
                else
                {
                    this.lblRegistering.Text = "Server unavailable";
                }
                // Failed attemp
                this.bgwProcessLogin.CancelAsync();
                e.Cancel = true;
                return;
            }
            // Report current progress
            this.bgwProcessLogin.ReportProgress(1, "Server available");
        }
        else
        {
            // User cancelled 
            e.Cancel = true;
            return;
        }
        .
        .
        .
}


 private void bgwProcessLogin_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {   
        // Check for any errors
        if (e.Error == null)
        {
            if (e.Cancelled)
            {
                // User cancelled login or login failed                
            }
            else
            {
                // Login completed successfully                
            }
        }
        else
        {
            // Something failed display error
            this.statusDisplay1.CallStatus = e.Error.Message;
        }
    }


 private void bgwProcessLogin_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.lblRegistering.Text = e.UserState.ToString();
    }

private void btnCancel_Click(object sender, EventArgs e)
    {
        // Cancel the logging in process
        this.bgwProcessLogin.CancelAsync();
        this.lblRegistering.Text = "Logged out";
}
Était-ce utile?

La solution

Il n’ya peut-être qu’un seul problème: si l’une des opérations dans le gestionnaire d’événements DoWork devait durer longtemps. Dans ce cas, vous pouvez abandonner votre opération en attente UNIQUEMENT après la fin de cette opération. Si toutes les opérations dans l'événement DoWork ne peuvent pas durer très longtemps (par exemple, pas plus de 5 secondes), tout est OK, mais si l'une des opérations peut durer longtemps (5 minutes, par exemple), dans ce cas, l'utilisateur doit attendre que cette opération soit terminée.

Si DoWork contient des opérations de longue durée, vous pouvez utiliser quelque chose comme AbortableBackgroundWorker. Quelque chose comme ça:

public class AbortableBackgroundWorker : BackgroundWorker
{
    private Thread workerThread;

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        workerThread = Thread.CurrentThread;
        try
        {
            base.OnDoWork(e);
        }
        catch (ThreadAbortException)
        {
            e.Cancel = true; //We must set Cancel property to true!
            Thread.ResetAbort(); //Prevents ThreadAbortException propagation
        }
    }


    public void Abort()
    {
        if (workerThread != null)
        {
            workerThread.Abort();
            workerThread = null;
        }
    }
}

Dans ce cas, vous pouvez vraiment abandonner les opérations en attente, mais vous devez également respecter certaines restrictions (pour plus d'informations sur l'abandon du fil géré et certaines restrictions, reportez-vous à la section Plomberie des profondeurs de l'exception ThreadAbortException à l'aide de Rotor ).

P.S. Je suis d’accord avec Oliver pour dire que vous devriez envelopper InvokeRequired sous une forme plus utilisable.

Autres conseils

Je pense que vous le faites correctement. Vous trouverez des membres de fil qui vous permettent de terminer ou d'abandonner un fil, mais vous ne voulez pas les utiliser pour quelque chose comme ça. Cela peut sembler un peu bizarre d’avoir toutes les "annulées" vérifie votre code, mais cela vous permet de contrôler exactement quand vous quittez votre thread. Si vous deviez "rudement" Abandonnez le thread de travail, le thread n’a aucun contrôle sur le moment où il se ferme et il pourrait y avoir un état corrompu.

Dans votre fonction DoWork (), vous avez écrit ... . En fonction du nombre de tâches de la même structure, comme les deux tâches affichées, vous pouvez refactoriser cette structure dans une propre méthode, en donnant les parties changeantes sous forme de paramètres.

Cette branche InvokeRequired if-else a également doublé la chaîne de sortie. Une petite recherche ici sur stackoverflow ou sur le Web devrait vous montrer un modèle permettant de doubler ce résultat.

Evernything else semble assez bon.

Il y a une chose pour laquelle je n'ai pas besoin d'appeler le this.bgwProcessLogin.CancelAsync (); comme vous pouvez simplement définir ceci e.Cancel = true;

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