代码之家  ›  专栏  ›  技术社区  ›  Charlie Lee

C#backgroundWorker取消和调用

  •  0
  • Charlie Lee  · 技术社区  · 7 年前

    我的代码大致如下:

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

    首先,while DnldBgWorker StopBtn 停止 异步工作不会停止。我该怎么停下来 DnldBgWorker公司

    第二 EditProcess.Text(String.Format("Downloaded: {0}\r\n"));

    ++)我的代码看起来像是在以非常复杂的方式完成非常简单的工作,但我在代码中加入了非常重要的元素,所以请理解

    4 回复  |  直到 7 年前
        1
  •  0
  •   Vikhram    7 年前

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

    1. 由于某些原因,在实际下载完成后,您有一个完全冗余的循环等待取消。因此 BtnStop
    2. 当你打电话的时候 EditProcess.Text 从…起 Dnld cross-thread operation here . 在你的情况下,你应该通过 ReportProgress

    现在你可以看到我

    1. GoDownload 在移动 if (DnldBgWorker.CancellationPending) 检查下载循环。这应该使 StopBtn
    2. 添加了 ProgressChanged ExecuteBtn_Click . 这是由 DnldBgWorker.ReportProgress 货物装载 方法这里我们将自定义格式的字符串传递为 UserState
    3. ReportsProgress SupportsCancellation 属性,可能在designer属性框或代码lile中 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;
        }
    }
    
        2
  •  0
  •   orhtej2    7 年前

    这里有两个问题:

    关于取消-你需要在下载的循环中检查取消状态(因此只下载部分请求的文件),而不是在我不太理解的后一个循环中。

    WebClient.DownloadFileAsync WebClient.CancelAsync 联合体。

    BackgroundWorker 通过将进度报告回UI线程 ReportProgress

        3
  •  0
  •   dacke.geo    7 年前

    至于如何取消线程。这是一个控制台应用程序的基本示例,我希望您可以将其放入更复杂的代码中。

    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...
    

    Updating Windows Form UI elements from another thread

        4
  •  0
  •   Steve    7 年前

    要支持取消,您需要设置属性

     DnldBgWorker.WorkerSupportsCancellation = true;
    

    不清楚您是否在其他地方设置了它,但您需要它来取消后台工作程序,因为您可以在MSDN上阅读

    支持取消的后台工作人员。当此属性为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));
    }
    

    DnldBgWorker.ReportProgress(i);