為什么需要進度條?
這里有200個左右的文件,每個文件里面有1000條數據庫插入語句,總共約200 000條記錄。
在單線程情況下,執行插入時界面會失去響應,完成插入需要長達8個小時。
不會有人認為界面沒有卡死,即使是我自己寫的程序,也不禁懷疑是否程序卡死。
進度條,以及各種執行情況顯示,在這種情況下真的很重要。
我還不明白為什么界面不能刷新,即使改變控件位置等等,因此目前只能采用多線程的方式實現進度條。
方式一
選擇控件
一個Button及ProgressBar
實現思路
由UI線程負責畫面刷新,另一個線程負責計算
窗體的字段this.count就是返回給進度條的數據
public partial class Form1 : Form { int count = 0;
這是模擬計算的函數,當然方法體也可以替換為實際的操作。
public void progress()//模擬執行一項耗時的操作 { bool add = true;//進度條增長 while (true) { while (add) { if (this.count == 10000)//進度條上限 { add = false; break; } this.count += 100;//要操作的數據 Thread.Sleep(100); } while (!add) { if (this.count == 0)//進度條下限 { add = true; break; } this.count -= 100; Thread.Sleep(100); } } }
在Button的點擊事件中,將這個函數傳遞給線程
private void button1_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(progress)); t.IsBackground = true;//在主界面關閉時此線程銷毀 t.Start(); }
此時點擊按鈕,this.count變化,但ProgressBar的Value沒變,要使Value變化,得不停的給Value賦值,因此增加一個Timer
private void timer1_Tick(object sender, EventArgs e) { this.progressBar1.Value = this.count; }
現在已經實現了進度條,並且由於是單獨的線程執行計算,界面並不會失去響應,任然是可互動的
結果
方式二
使用委托,將progress()傳遞給委托,另定義call方法,使用invoke方法解決調用線程無法訪問此對象的問題
public delegate void Draw(); Draw draw; private void button1_Click(object sender, EventArgs e) { draw = new Draw(progress);//在使用Invoke時才需要委托 //Control.CheckForIllegalCrossThreadCalls = false; Thread t = new Thread(new ThreadStart(call)); //Thread t = new Thread(new ThreadStart(progress)); t.IsBackground = true;//在主界面關閉時此線程銷毀 t.Start(); } public void call() { while (true) { progressBar1.Invoke(draw);//似乎是提交給UI線程運行,UI線程在執行完自己代碼后才會執行Invoke提交的代碼 } }
invoke方法雖然是在新創建的線程中調用的,但根據網上一些資料以及我自己的實驗,invoke應當還是由UI線程在執行,也就是說progress()由UI線程在執行,並沒有解決計算與更新分離的問題,雖然這是網上大部分資料的方式
而且這種方法界面雖然更新,但是沒有響應
改寫progress()
public void progress()//模擬執行一項耗時的操作 { bool add = true;//進度條增長 while (true) { while (add) { if (this.count == 10000) { add = false; break; } this.count += 100; this.progressBar1.Value = this.count;//此處新增 Thread.Sleep(100); } while (!add) { if (this.count == 0) { add = true; break; } this.count -= 100; this.progressBar1.Value = this.count;//此處新增 Thread.Sleep(100); } } }
停止使用Timer
結果
雖然實現了進度條,但是與界面不能互動,窗體處於無響應狀態