Domanda

C # 2008

Sto utilizzando il codice seguente per accedere a un softphone. Tuttavia, il processo di accesso è un lungo processo in quanto ci sono molte cose che devono essere inizializzate e controlli da effettuare, ne ho messi solo alcuni qui, poiché renderebbe troppo lungo pubblicare il codice.

Nel codice qui sotto sto verificando se il CancelPending se il CancelAsync è stato chiamato nel mio evento click sul pulsante Annulla, prima di effettuare ogni controllo. È corretto? Inoltre, se il controllo fallisce, chiamo anche CancelAsync e imposto e.Cancel su true.

Vorrei sapere se il mio metodo che ho usato qui è il metodo migliore da usare.

Mille grazie per qualsiasi consiglio

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";
}
È stato utile?

Soluzione

C'è forse un solo problema: se una delle operazioni nel gestore eventi DoWork durerà a lungo. In questo caso, è possibile interrompere l'operazione in sospeso SOLO al termine dell'operazione. Se tutte le operazioni nell'evento DoWork non possono durare a lungo (ad esempio, non più di 5 secondi), è tutto OK, ma se una delle operazioni può durare a lungo (5 minuti, ad esempio) in questo caso l'utente ha attendere fino al termine di questa operazione.

Se DoWork contiene operazioni di lunga durata, puoi usare qualcosa come AbortableBackgroundWorker. Qualcosa del genere:

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

In questo caso puoi veramente interrompere le operazioni in sospeso, ma hai anche alcune restrizioni (per maggiori informazioni sull'interruzione del thread gestito e alcune restrizioni vedi Idraulico delle profondità di ThreadAbortException mediante il rotore ).

P.S. Sono d'accordo con Oliver che dovresti avvolgere InvokeRequired in una forma più utilizzabile.

Altri suggerimenti

Lo stai facendo nel modo giusto, credo. Troverai membri del thread che ti consentono di terminare o interrompere un thread, ma non vuoi usarli per qualcosa del genere. Potrebbe sembrare un po 'strano avere tutti i "annullati" controlla il tuo codice, ma ciò ti consente di controllare esattamente quando esci dal thread. Se dovessi "maleducato" interrompere il thread di lavoro, il thread non ha alcun controllo su quando esce e potrebbe esserci stato danneggiato.

All'interno della funzione DoWork () hai scritto ... . A seconda di quante attività della stessa struttura stanno arrivando come le due visualizzate, è possibile trasformare questa struttura in un proprio metodo, fornendo le parti modificabili come parametri.

Anche questo ramo if-else InvokeRequired ha raddoppiato la stringa di output. Una piccola ricerca qui su StackOverflow o sul Web dovrebbe mostrarti uno schema per realizzare questo raddoppio.

Tutto il resto sembra abbastanza buono.

C'è una cosa che non ho bisogno di chiamare this.bgwProcessLogin.CancelAsync (); come puoi semplicemente impostare questo e.Cancel = true;

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top