4

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

4 回答 4

8

可能只有一个问题: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;
        }
    }
}

在这种情况下,您可以真正中止挂起的操作,但您也有一些限制(有关中止托管线程的更多信息和一些限制,请参阅Plumbing the Depths of the ThreadAbortException Using Rotor)。

PS 我同意 Oliver 的观点,即您应该将 InvokeRequired 包装成更可用的形式。

于 2010-01-29T08:13:53.590 回答
1

你做对了,我相信。您会发现允许您终止或中止线程的线程成员,但您不想将它们用于此类事情。在您的代码中包含所有“取消”检查可能看起来有点奇怪,但这允许您准确控制何时退出线程。如果你“粗鲁地”中止工作线程,线程无法控制它何时退出,并且可能存在损坏状态。

于 2009-05-05T19:29:33.590 回答
1

在您编写的 DoWork() 函数...中。根据显示的两个相同结构的任务的数量,您可以将此结构重构为自己的方法,将变化的部分作为参数。

这个 InvokeRequired if-else 分支也将输出字符串加倍。在 stackoverflow 或网络上进行一点搜索应该会向您展示实现这种加倍的模式。

其他一切看起来都很好。

于 2010-01-29T07:57:28.303 回答
0

有一件事我不需要调用 this.bgwProcessLogin.CancelAsync(); 因为你可以设置这个 e.Cancel = true;

于 2009-05-06T15:13:32.403 回答