繁体   English   中英

C#backgroundWorker取消和调用

[英]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.DownloadFileAsyncWebClient.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);

在进入代码之前,让我们解决这个问题

  1. 出于某种原因,您有一个完全冗余的循环,在完成实际下载后,等待取消。 因此, BtnStop对您不起作用
  2. 当你调用EditProcess.TextDnld这是在BackgroundWorker的上下文中调用,您从一个线程这不“拥有”它访问GUI元素。 您可以在此处详细阅读有关跨线程操作的信息 对于您的情况,应该通过ReportProgress调用来完成。

现在你可以看到我的情况了

  1. if (DnldBgWorker.CancellationPending)检查移至下载循环时,从GoDownload删除了冗余循环。 这应该使StopBtn工作。
  2. 添加了ProgressChanged事件处理程序以在ExecuteBtn_Click进行GUI更改。 这是由触发DnldBgWorker.ReportProgress在下载循环调用GoDownload方法。 在这里,我们将自定义格式的字符串作为UserState传递
  3. 还要确保您已启用了如下所示的ReportsProgressSupportsCancellation属性,可能是在设计器属性框中,也可能是在代码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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM