C # отмена DoWork фонового работника - PullRequest
4 голосов
/ 05 мая 2009

C # 2008

Я использую код ниже для входа в софтфон. Тем не менее, процесс входа в систему является длительным процессом, так как есть много вещей, которые должны быть инициализированы и проверки должны быть сделаны, я только поставил несколько здесь, так как это сделает код длинным для публикации.

В приведенном ниже коде я проверяю, был ли CancellationPending, если CancelAsync был вызван в моем событии нажатия кнопки отмены, перед выполнением каждой проверки. Это правильно? Также, если проверка не пройдена, я также вызываю функцию CancelAsync и устанавливаю значение e.Cancel в значение true.

Я хотел бы знать, является ли мой метод, который я использовал здесь, лучшим методом для использования.

Большое спасибо за любой совет,

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

Ответы [ 4 ]

8 голосов
/ 29 января 2010

Возможно, есть только одна проблема: если одна из операций в обработчике событий DoWork будет длиться долго. В этом случае вы можете прервать ожидающую операцию ТОЛЬКО после ее завершения. Если все операции в событии DoWork не могут длиться очень долго (например, не более 5 секунд), все в порядке, но если одна из операций может длиться долго (например, 5 минут), в этом случае пользователь должен ждать до завершения этой операции.

Если DoWork содержит длительные операции, вы можете использовать что-то вроде AbortableBackgroundWorker. Примерно так:

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

В этом случае вы можете действительно прервать ожидающие операции, но у вас также есть некоторые ограничения (для получения дополнительной информации об отмене управляемого потока и некоторых ограничениях см. Определение глубины исключения ThreadAbortException с помощью Rotor ).

P.S. Я согласен с Оливером, что вам следует заключить InvokeRequired в более удобную форму.

1 голос
/ 29 января 2010

В вашей функции DoWork () вы написали .... В зависимости от того, сколько задач одной и той же структуры поступает подобно отображаемым двум, вы можете преобразовать эту структуру в собственный метод, предоставив изменяющиеся части в качестве параметров.

Также эта ветвь InvokeRequired if-else удвоила выходную строку. Небольшой поиск здесь в stackoverflow или в Интернете должен показать вам шаблон для достижения этого удвоения.

Все остальное выглядит неплохо.

1 голос
/ 05 мая 2009

Вы делаете это правильно, я считаю. Вы найдете членов потока, которые позволяют вам прекратить или прервать поток, но вы не хотите использовать их для чего-то подобного. Может показаться немного странным иметь все «отмененные» проверки в вашем коде, но это позволяет вам точно контролировать выход из потока. Если вы должны были «грубо» прервать рабочий поток, этот поток не контролировал бы, когда он выходит, и могло быть поврежденное состояние.

0 голосов
/ 06 мая 2009

Есть одна вещь, которую мне не нужно вызывать this.bgwProcessLogin.CancelAsync (); как вы можете просто установить это e.Cancel = true;

...