星期四, 2月 23, 2017

[C#] BackgroundWorker 範例4

閱讀這篇 MSDN 文章 如何:在背景中下載檔案,發現兩個重點
請務必檢查您 RunWorkerCompleted 事件處理常式中的 AsyncCompletedEventArgs.Error 屬性,再嘗試存取可能會受 DoWork 事件處理常式影響的 RunWorkerCompletedEventArgs.Result 屬性或任何其他物件。
XXXEventArgs 通常都是 Event 第二參數,RunWorkerCompleted Event 明明就是 RunWorkerCompletedEventArgs,只能自行解讀為要先判斷 RunWorkerCompletedEventArgs.Cancel 和 RunWorkerCompletedEventArgs.Error,再來存取 RunWorkerCompletedEventArgs.Result

在 RunWorkerCompletedEventArgs.Result 內也有相關說明
您 RunWorkerCompleted 事件處理常式應該一律檢查 Error 和 Cancelled 屬性,然後再存取 Result 屬性。 如果發生例外狀況,或已取消作業,存取 Result 屬性引發例外狀況。
Application.DoEvents 的存在,可以讓迴圈進行時,UI 還可以進行操作,但該作法會造成 CPU 飆高,所以要利用 Thread.Sleep 睡一下,該效果透過工作管理員就可以觀察到
while (this.backgroundWorker1.IsBusy)
{
    progressBar1.Increment(1);
    // Keep UI messages moving, so the form remains 
    // responsive during the asynchronous operation.
    Application.DoEvents();
    // 避免 CPU 飆高
    Thread.Sleep(1);
}

該範例 Code 整理
using System.Xml;
using System.Threading;

namespace BackgroundWorkerDownload
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
            backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;
        }

        private XmlDocument document = null;

        private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Set progress bar to 100% in case it's not already there.
            progressBar1.Value = 100;

            if (e.Error == null)
            {
                MessageBox.Show(document.InnerXml, "下載完成");
            }
            else
            {
                MessageBox.Show("無法下載檔案,下載失敗", "下載檔案", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            // Enable the download button and reset the progress bar.
            btnDownload.Enabled = true;
            progressBar1.Value = 0;
        }

        private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            document = new XmlDocument();

            Thread.Sleep(10000);

            // Replace this file name with a valid file name.
            document.Load(@"http://www.tailspintoys.com/sample.xml");
        }

        private void btnDownload_Click(object sender, EventArgs e)
        {
            // Start the download operation in the background.
            backgroundWorker1.RunWorkerAsync();

            // Disable the button for the duration of the download.
            btnDownload.Enabled = false;

            // Once you have started the background thread you 
            // can exit the handler and the application will 
            // wait until the RunWorkerCompleted event is raised.

            // Or if you want to do something else in the main thread,
            // such as update a progress bar, you can do so in a loop 
            // while checking IsBusy to see if the background task is
            // still running.
            while (this.backgroundWorker1.IsBusy)
            {
                progressBar1.Increment(1);
                // Keep UI messages moving, so the form remains 
                // responsive during the asynchronous operation.
                Application.DoEvents();
                // 避免 CPU 飆高
                Thread.Sleep(1);
            }
        }
    }
}

沒有留言:

張貼留言