1. 程式人生 > >C#呼叫耗時函式時顯示進度條淺探

C#呼叫耗時函式時顯示進度條淺探

最近在做一個VSS日誌分析工具,使用C#進行開發,在完成了所有功能後,發現,從伺服器下載VSS日誌非常耗時,因為此,導致工具使用體驗不好,所以,準備增加一個進度條。
鑑於C#不經常使用,一下子搞個進度條貌似比較難,而且其他的開發任務也在一併進行,所以,昨天一天,並沒有多大的進展。
今天,是週末,正好可以利用,在查閱了大量網上資料以及例項後,我製作了幾個例項,以備後來之用。
使用C#顯示進度條,涉及到多執行緒程式設計,我只探索了使用BackgroundWorker和Thread的方法,下面分別列出。

第一種:使用BackgroundWorker進行進度條控制
BackgroundWorker物件有三個主要的事件:
DoWork - 當BackgroundWorker物件的多執行緒操作被執行時觸發。
RunWokerCompleted - 當BackgroundWoker物件的多執行緒操作完成時觸發。
ProgressChanged - 當BackgroundWorker物件的多執行緒操作狀態改變時觸發。
WorkerReportsProgress - 如果想讓BackgroundWorker物件以非同步的方式報告執行緒實時進度,必須將該屬性的值設為true。
BackgroundWorker物件的ReportProgress方法用於向主執行緒返回後臺執行緒執行的實時進度。

例項程式碼一,控制主窗體中的進度條顯示

    public partial class Form1 : Form
    {
        /// <summary>
        /// 後臺執行緒
        /// </summary>
        private BackgroundWorker bkWorker = new BackgroundWorker();

        /// <summary>
        /// 步進值
        /// </summary>
        private int percentValue = 0;

        public Form1()
        {
            InitializeComponent();

            bkWorker.WorkerReportsProgress = true;
            bkWorker.WorkerSupportsCancellation = true;
            bkWorker.DoWork += new DoWorkEventHandler(DoWork);
            bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged);
            bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            percentValue = 10;
            this.progressBar1.Maximum = 1000;
            // 執行後臺操作
            bkWorker.RunWorkerAsync();
        }

        public void DoWork(object sender, DoWorkEventArgs e)
        {
            // 事件處理,指定處理函式
            e.Result = ProcessProgress(bkWorker, e);
        }

        public void ProgessChanged(object sender, ProgressChangedEventArgs e)
        {
            // bkWorker.ReportProgress 會呼叫到這裡,此處可以進行自定義報告方式
            this.progressBar1.Value = e.ProgressPercentage;
            int percent = (int)(e.ProgressPercentage / percentValue);
            this.label1.Text = "處理進度:" + Convert.ToString(percent) + "%";
        }

        public void CompleteWork(object sender, RunWorkerCompletedEventArgs e)
        {
            this.label1.Text = "處理完畢!";
        }

        private int ProcessProgress(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i <= 1000; i++)
            {
                if (bkWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return -1;
                }
                else
                {
                    // 狀態報告
                    bkWorker.ReportProgress(i);

                    // 等待,用於UI重新整理介面,很重要
                    System.Threading.Thread.Sleep(1);
                }
            }

            return -1;
        }
    }

下面是執行結果


例項程式碼二,控制彈出窗體中的進度條顯示
主窗體程式碼:

    public partial class Form1 : Form
    {
        private BackgroundWorker bkWorker = new BackgroundWorker();
        private Form2 notifyForm = new Form2();

        public Form1()
        {
            InitializeComponent();

            // 使用BackgroundWorker時不能在工作執行緒中訪問UI執行緒部分,
            // 即你不能在BackgroundWorker的事件和方法中操作UI,否則會拋跨執行緒操作無效的異常
            // 新增下列語句可以避免異常。
            CheckForIllegalCrossThreadCalls = false;

            bkWorker.WorkerReportsProgress = true;
            bkWorker.WorkerSupportsCancellation = true;
            bkWorker.DoWork += new DoWorkEventHandler(DoWork);
            bkWorker.ProgressChanged += new ProgressChangedEventHandler(ProgessChanged);
            bkWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompleteWork);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            notifyForm.StartPosition = FormStartPosition.CenterParent;

            bkWorker.RunWorkerAsync();
            notifyForm.ShowDialog();
        }

        public void DoWork(object sender, DoWorkEventArgs e)
        {
            // 事件處理,指定處理函式
            e.Result = ProcessProgress(bkWorker, e);
        }

        public void ProgessChanged(object sender, ProgressChangedEventArgs e)
        {
            // bkWorker.ReportProgress 會呼叫到這裡,此處可以進行自定義報告方式
            notifyForm.SetNotifyInfo(e.ProgressPercentage, "處理進度:" + Convert.ToString(e.ProgressPercentage) + "%");
        }

        public void CompleteWork(object sender, RunWorkerCompletedEventArgs e)
        {
            notifyForm.Close();
            MessageBox.Show("處理完畢!");
        }

        private int ProcessProgress(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i <= 1000; i++)
            {
                if (bkWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return -1;
                }
                else
                {
                    // 狀態報告
                    bkWorker.ReportProgress(i / 10);

                    // 等待,用於UI重新整理介面,很重要
                    System.Threading.Thread.Sleep(1);
                }
            }

            return -1;
        }
    }
子窗體程式碼
   public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public void SetNotifyInfo(int percent, string message)
        {
            this.label1.Text = message;
            this.progressBar1.Value = percent;
        }
    }

下面是執行結果


第二種,使用Thread來實現
使用Thread實現,雖然步驟上比較麻煩,但是呼叫流程比較簡單,也是一種可以參考的方法
使用時,首先要定義代理以及函式,然後實現執行緒函式,線上程函式中呼叫代理,最後啟動執行緒,傳入執行緒函式。
下面是例項程式碼:

    public partial class Form1 : Form
    {
        private Form2 progressForm = new Form2();
        // 代理定義,可以在Invoke時傳入相應的引數
        private delegate void funHandle(int nValue);
        private funHandle myHandle = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            // 啟動執行緒
            System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadFun));
            thread.Start();
        }

        /// <summary>
        /// 執行緒函式中呼叫的函式
        /// </summary>
        private void ShowProgressBar()
        {
            myHandle = new funHandle(progressForm.SetProgressValue);
            progressForm.ShowDialog();
        }

        /// <summary>
        /// 執行緒函式,用於處理呼叫
        /// </summary>
        private void ThreadFun()
        {
            MethodInvoker mi = new MethodInvoker(ShowProgressBar);
            this.BeginInvoke(mi);

            System.Threading.Thread.Sleep(1000); // sleep to show window

            for (int i = 0; i < 1000; ++i)
            {
                System.Threading.Thread.Sleep(5);
                // 這裡直接呼叫代理
                this.Invoke(this.myHandle, new object[] { (i / 10) });
            }
        }
    }
子窗體程式碼
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        public void SetProgressValue(int value)
        {
            this.progressBar1.Value = value;
            this.label1.Text = "Progress :" + value.ToString() + "%";

            // 這裡關閉,比較好,呵呵!
            if (value == this.progressBar1.Maximum - 1) this.Close();
        }
    }

下面是執行結果圖


參考資料

1. C#進度條實現例項 { http://www.csharpwin.com/csharpspace/6546r2922.shtml }
2. 使用BackgroundWorker方便地實現多執行緒進度條!{ http://www.coderblog.in/2011/03/backgroundworker-for-progreessbar.html }
3. 多執行緒:C#.NET中使用BackgroundWorker在模態對話方塊中顯示進度條 { http://www.mysjtu.com/page/M0/S536/536907.html }
4. C#進度條在彈出視窗中顯示的實現 { http://wenku.baidu.com/view/9f9d89d2240c844769eaeeff.html }

相關推薦

C#呼叫耗時函式顯示進度

最近在做一個VSS日誌分析工具,使用C#進行開發,在完成了所有功能後,發現,從伺服器下載VSS日誌非常耗時,因為此,導致工具使用體驗不好,所以,準備增加一個進度條。 鑑於C#不經常使用,一下子搞個進度條貌似比較難,而且其他的開發任務也在一併進行,所以,昨天一天,並沒有多大的

POI匯出資料並且實現匯出顯示進度

js程式碼 /* 進度條隱藏 */                 function modalClose() {       

C# Winform下載檔案並顯示進度

本來是要研究怎樣判斷下載完成,結果找到這個方法,可以在這個方法完成之後提示下載完成。 程式碼如下: using System; using System.Collections.Generic; using System.ComponentModel; usin

WebView 載入資料顯示進度,載入完後再把進度取消並顯示內容

轉載地址:http://blog.sina.com.cn/s/blog_7a66361301011a46.html webview 載入資料時顯示進度條有兩種. 第一種方法 這個是載入資料時顯示進度條 super.onCreate(savedInstanceState);

C# 時間控件 豎直進度 餅圖顯示 按鈕基礎控件庫

種類型 ins 控制 按鈕 顏色 微軟 rgs mas 機制 Prepare 本文將使用一個NuGet公開的組件來實現一些特殊的控件顯示,方便大家進行快速的開發系統。 在Visual Studio 中的NuGet管理器中可以下載安裝,也可以直接在NuGet控制臺輸入

Linux C實現檔案拷貝可變色進度顯示

printf的格式化輸出中,可以設定前景色和背景色,因此進度條的顏色可以通過printf的格式化輸出來實現;此外,進度條的實現主要依靠"\r"和"fflush(stdout)“來支援。”\r" 用來回到行首而不換行,fflush(stdout)是重新整理螢幕輸出

【lua】C 函式呼叫Lua函式,對於lua_pcall使用的困惑

最近在學習使用Lua,也通過基本的語法知識完成了公司的一個關於配置檔案引數合法性檢查的小任務。雖然任務完成了,但對於一些函式的呼叫目的還是搞不明白,這兩天再次重看了Manual Reference,稍微梳理出了一點眉目,記錄在此。 首先看一段小小小程式 fun

C 函式呼叫Lua函式,對於lua_pcall使用的困惑

最近在學習使用Lua,也通過基本的語法知識完成了公司的一個關於配置檔案引數合法性檢查的小任務。雖然任務完成了,但對於一些函式的呼叫目的還是搞不明白,這兩天再次重看了Manual Reference,稍微梳理出了一點眉目,記錄在此。 首先看一段小小小程式 //test.lua

多執行緒:C#.NET中使用BackgroundWorker在模態對話方塊中顯示進度

我們使用C#.NET編寫WinForm程式時,有時候為了實現在模態對話方塊中實時顯示後臺操作的進度,這個時候需要藉助於多執行緒操作在子窗體中顯示進度條狀態,在父窗體中進行後臺操作。你可以在Thread類中自己建立兩個執行緒以完成這個操作,不過C#.NET提供了Backgro

C/C++ 在控制檯下顯示進度

當程式在進行大量的運算或IO操作時,常常需要耗很長時間,為了不讓使用者有一個乏味的等待或是錯誤的認為系統已經宕機,有必要給程式新增進度提示功能。在視窗介面中要顯示進度條和顯示完成百分比是非常容易的,但如何在控制檯下去完成這個任務了?一行一行的輸出當前完成百分比肯定是不夠美

C#控制檯顯示進度

class Program     {         static void Main(string[] args)         {             bool isBreak = false;             ConsoleColor colorBack

cp顯示進度

trap oms rom pri span 進度 pan 進度條 color #!/bin/bash trap ‘exit_fun‘ 2 usage(){ echo "Usage: `basename $0` \"src file\" \"ds

Python獲取下載速度並顯示進度

locks rom art 回調 filename bytes sleep format == #!/usr/bin/python3 # -*- coding:utf-8 -*- import sys import time from urllib impo

基於Jquery插件Uploadify實現實時顯示進度上傳圖片

準備 深入學習 pla 回調 true bar put and 分割 網址:http://www.jb51.net/article/83811.htm 這篇文章主要介紹了基於Jquery插件Uploadify實現實時顯示進度條上傳圖片的相關資料,感興趣的小夥伴們可

delphi CopyFileProgressBar 拷貝文件顯示進度

items path adb sets sage app sts min ets CopyFileProgressBar(pwidechar(ListBox1.Items.Strings[I]),pwidechar(NewDir+‘\‘+ExtractFileName(L

js 文件異步上傳 顯示進度 顯示上傳速度 預覽文件

response null acc 文件的 pen 實現 accept https 提交 通常文件異步提交有幾個關鍵 1.支持拖拽放入文件。2.限制文件格式。3.預覽圖片文件。4.上傳進度,速度等,上傳途中取消上傳。5.數據與文件同時上傳 現在開始筆記: 需要一個最基礎的元

[C#] 多線程總結(結合進度)

ali .repo pro 上下文 回調函數 實例 blank type 後臺 線程生命周期 未啟動狀態:當線程實例被創建但 Start 方法未被調用時的狀況。 就緒狀態:當線程準備好運行並等待 CPU 周期時的狀況。 不可運行狀態: 已經調用 Sleep 方法 已經調

python 迴圈中顯示進度

import sys # 迴圈時顯示進度條 # total 代表迴圈總數 ,num為當前迴圈數 def view_bar(num, total): rate = float(num) / float(total) rate_num = int(rate * 100)

CentOS7開機進度介面卡死

起因 自己在公司一臺主機上安裝了幾個centos7的虛擬機器用來給同事練手/測試,前段時間停電的緣故導致機器關機,重啟後發現其中一臺虛擬機器無法啟動,進度條很慢,並且進度條滿了之後就一直卡在這個介面不能進入系統,今天剛好需要用到就搜了下解決辦法。 主要參考了下面文章: Linux基

Python網路爬蟲之製作股票資料定向爬蟲 以及爬取的優化 可以顯示進度

候選網站: 新浪股票:http://finance.sina.com.cn/stock/ 百度股票:https://gupiao.baidu.com/stock/ 選取原則: 無robots協議 非js網頁 資料在HTMLK頁面中的 F12,檢視原始