[英]C# backgroundWorker cancellation and invoke
关于backgroundWorker,我有两个问题:一个是取消,另一个是调用。
我的代码简要如下:
public partial class App : Form {
//Some codes omitted
public EditProcess Process = new EditProcess(ProcessTextBox);
private void ExecuteBtn_Click (object sender, EventArgs e) {
//DnldBgWorker is a backgroundWorker.
Download Dnld = new Download(dir, Process);
DnldBgWorker.DoWork += (obj, e) => GoDownload(Dnld, urllist, e);
DnldBgWorker.RunWorkerAsync();
DnldBgWorker.RunWorkerCompleted += (obj, e) => FinishExecution();
}
private void GoDownload(Download Dnld, string[] urllist, EventArgs e) {
foreach(string url in urllist) {
Dnld.Dnld(url);
}
for (int i = 0; i < 10; i++) {
System.Threading.Thread.Sleep(50);
if (DnldBgWorker.CancellationPending) {
e.Cancel = true;
return;
}
}
}
private void StopBtn_Click(object sender, EventArgs e) {
DnldBgWorker.CancelAsync();
}
}
public class Download {
// Some codes omitted
public WebClient client = new WebClient();
public EditProcess Process;
public Download(string dir, EditProcess Process) {
this.dir = dir;
this.Process = Process;
}
public void Dnld() {
client.DownloadFile(url, dir);
EditProcess.Text(String.Format("Downloaded: {0}\r\n"));
}
}
public class EditProcess {
public TextBox Box;
public EditProcess(TextBox Box) {
this.Box = Box;
}
public void Text(string textToAdd) {
Box.Text += textToAdd;
}
}
首先,当DnldBgWorker
运行时,我单击StopBtn
以停止DnldBgWorker
,并且异步工作不会停止。 我应该如何停止DnldBgWorker
?
其次, EditProcess.Text(String.Format("Downloaded: {0}\\r\\n"));
会给我一个错误,指出跨线程操作无效。 我知道我应该委派一名代表来执行此操作,但是我不知道具体如何做。
++)我的代码看起来以非常复杂的方式完成了非常简单的工作,但是我在代码中加入了非常重要的元素,因此请理解
这里有两个问题:
关于取消-您需要在进行下载的循环中检查取消状态(因此仅下载部分请求的文件),而不是在我不太了解的以后的循环中。
另外,您可以避免通过使用WebClient.DownloadFileAsync
和WebClient.CancelAsync
组合使用BackgroundWorker。
从报告进度开始-让BackgroundWorker
通过ReportProgress
将进度报告回到UI线程,并从那里更新UI。
至于如何取消线程。 这是一个控制台应用程序的基本示例,希望您可以将其放入更复杂的代码中。
void Main()
{
var tokenSource = new CancellationTokenSource();
System.Threading.Tasks.Task.Run(() => BackgroundThread(tokenSource.Token));
Thread.Sleep(5000);
tokenSource.Cancel();
}
private void BackgroundThread(CancellationToken token)
{
while (token.IsCancellationRequested == false) {
Console.Write(".");
Thread.Sleep(1000);
}
Console.WriteLine("\nCancellation Requested Thread Exiting...");
}
结果如下。
.....
Cancellation Requested Thread Exiting...
其次,关于如何从线程中调用以与用户界面进行交互,希望该博客对您有所帮助。 从另一个线程更新Windows Form UI元素
如果您觉得这有帮助,请告诉我。
要支持取消,您需要设置属性
DnldBgWorker.WorkerSupportsCancellation = true;
目前尚不清楚是否将其设置在其他位置,但是您需要它来取消后台工作程序,因为您可以在MSDN上阅读
如果您希望BackgroundWorker支持取消,则将WorkerSupportsCancellation属性设置为true。 当此属性为true时,可以调用CancelAsync方法来中断后台操作。
我也将GoDownload方法更改为
private void GoDownload(Download Dnld, string[] urllist, EventArgs e)
{
foreach(string url in urllist)
{
Dnld.Dnld(url);
// this is just to give more time to test the cancellation
System.Threading.Thread.Sleep(500);
// Check the cancellation after each download
if (DnldBgWorker.CancellationPending)
{
e.Cancel = true;
return;
}
}
}
对于第二个问题,您需要在代码在UI线程而不是后台线程上运行时调用该方法。 您可以轻松地在ProgressChanged事件的事件处理程序中移动文本框更新。 要设置事件处理程序,您需要将另一个属性设置为true
DnldBgWorker.WorkerReportsProgress = true;
并为ProgressChanged事件设置事件处理程序
DnldBgWorker.ProgressChanged += DnldBgWorker_ProgressChanged;
private void DnldBgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
EditProcess.Text(String.Format("Downloaded: {0}\r\n", e.ProgressPercentage));
}
并在GoDownload中通过
DnldBgWorker.ReportProgress(i);
在进入代码之前,让我们解决这个问题
BtnStop
对您不起作用 EditProcess.Text
从Dnld
这是在BackgroundWorker的上下文中调用,您从一个线程这不“拥有”它访问GUI元素。 您可以在此处详细阅读有关跨线程操作的信息 。 对于您的情况,应该通过ReportProgress
调用来完成。 现在你可以看到我的情况了
if (DnldBgWorker.CancellationPending)
检查移至下载循环时,从GoDownload
删除了冗余循环。 这应该使StopBtn
工作。 ProgressChanged
事件处理程序以在ExecuteBtn_Click
进行GUI更改。 这是由触发DnldBgWorker.ReportProgress
在下载循环调用GoDownload
方法。 在这里,我们将自定义格式的字符串作为UserState
传递 ReportsProgress
和SupportsCancellation
属性,可能是在设计器属性框中,也可能是在代码DnldBgWorker.WorkerReportsProgress = true; DnldBgWorker.WorkerSupportsCancellation = true;
DnldBgWorker.WorkerReportsProgress = true; DnldBgWorker.WorkerSupportsCancellation = true;
希望下面的代码对其他所有内容都清楚。
public partial class App : Form {
//Some codes omitted
public EditProcess Process = new EditProcess(ProcessTextBox);
private void ExecuteBtn_Click (object sender, EventArgs e) {
//DnldBgWorker is a backgroundWorker.
Download Dnld = new Download(dir, Process);
DnldBgWorker.DoWork += (obj, e) => GoDownload(Dnld, urllist, e);
DnldBgWorker.RunWorkerAsync();
DnldBgWorker.RunWorkerCompleted += (obj, e) => FinishExecution();
DnldBgWorker.ProgressChanged += (s, e) => EditProcess.Text((string)e.UserState);;
}
private void GoDownload(Download Dnld, string[] urllist, EventArgs e) {
foreach(string url in urllist) {
Dnld.Dnld(url);
DnldBgWorker.ReportProgress(0, String.Format($"Downloaded: {url}\r\n"));
if (DnldBgWorker.CancellationPending) {
e.Cancel = true;
return;
}
}
}
private void StopBtn_Click(object sender, EventArgs e) {
DnldBgWorker.CancelAsync();
}
}
public class Download {
// Some codes omitted
public WebClient client = new WebClient();
public EditProcess Process;
public Download(string dir, EditProcess Process) {
this.dir = dir;
this.Process = Process;
}
public void Dnld() {
client.DownloadFile(url, dir);
}
}
public class EditProcess {
public TextBox Box;
public EditProcess(TextBox Box) {
this.Box = Box;
}
public void Text(string textToAdd) {
Box.Text += textToAdd;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.