[英]C# cancelling DoWork of background worker
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";
}
可能只有一个问题:如果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;
}
}
}
在这种情况下,您可以真正中止挂起的操作,但您也有一些限制(有关中止托管线程的更多信息和一些限制,请参阅使用Rotor管道ThreadAbortException的深度 )。
PS我同意Oliver你应该以更实用的形式包装InvokeRequired。
在您编写的DoWork()函数中...
根据显示的两个任务的相同结构的任务数量,您可以将此结构重构为自己的方法,将更改的部分作为参数。
此InvokeRequired if-else分支也使输出字符串加倍。 在stackoverflow或web上进行一点搜索应该会显示一个模式来完成这个加倍。
其他东西看起来很不错。
我相信你正在以正确的方式做到这一点。 您将找到允许您终止或中止线程的线程成员,但您不希望将它们用于此类内容。 在代码中进行所有“取消”检查可能看起来有点奇怪,但这可以让您准确控制退出线程的时间。 如果您“粗暴地”中止工作线程,则线程无法控制何时退出,并且可能存在损坏的状态。
有一件事我不需要调用this.bgwProcessLogin.CancelAsync(); 因为你可以设置这个e.Cancel = true;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.