只是想在WPF中使用熟悉的Process Bar,那就別花時間看這篇了
到 youtube去搜尋比較快
這篇不會提到Process Bar,雖然同樣的原理也能用在Process Bar,甚至是自訂的任何進度條。這篇還順便迴避某些書中範例
無法回傳string的問題。
原因是WPF畫面的呈現和背景工作是分開的
當程式在忙碌時,畫面會乖乖的一直等背景工作跟他說OK才刷新
(圖片看起來會動,就是因為畫面不斷的刷新喔!)
想像影片前半段,希望能夠「圖片會動、文字會逐項目顯示」,那就需要用到
Async 和 Await
來寫出非同步程式,這樣畫面就不會等到海枯石爛了!
沒聽過「非同步, await, async」的也不用擔心,可以先理解差異,有興趣再找資料吧
●先來一段失敗的程式碼
private void test_Click(object sender, RoutedEventArgs e)
{
//沒使用async & await
showLog.Text = "轉檔開始(2秒/個)\r\n";
for (int i = 0; i < 3; i++)
{
showLog.Text += "開始第" + (int)(i + 1) + "個轉檔...";
Thread.Sleep(2000); //模擬轉檔時會停頓的時間
showLog.Text += "End\r\n";
}
showLog.Text += "轉檔全部結束\r\n";
}
●然後這是成功的程式碼
private async void test_Click(object sender, RoutedEventArgs e)
{
//使用async & await
showLog.Text = "轉檔開始(2秒/個)\r\n";
for (int i = 0; i < 3; i++)
{
showLog.Text += "開始第" + (int)(i + 1) + "個轉檔...";
showLog.Text += await ConvertFile("End\r\n");
}
showLog.Text += "轉檔全部結束\r\n";
}
public Task<string> ConvertFile(string str)
{
return Task.Factory.StartNew(() => this._ConvertFile(str));
}
public string _ConvertFile(string para1) {
Thread.Sleep(2000); //模擬轉檔時會停頓的時間
return para1;
}
知道怎麼套用await和async,讓畫面不會卡住了嗎?
還是不懂的話,再繼續往下看吧
1. 在可能會執行到需要花時間,但前後想加上其他程式碼的方法(method)的宣告加上「async」,這樣之後要加的await才有作用。只加async卻沒加await,也不會有作用的喔!
before:
private void test_Click(object sender, RoutedEventArgs e){...}
after:
private async void test_Click(object sender, RoutedEventArgs e){...}
2. 宣告一個回傳「數值或字串」的方法 (※不見得要寫成能傳參數,只寫"public string _ConverFile()"也行)
before:
private async void test_Click(object sender, RoutedEventArgs e){
...
Thread.Sleep(2000); //模擬轉檔時會停頓的時間
...
}
after:
private async void test_Click(object sender, RoutedEventArgs e){
...
//Thread.Sleep(2000); //將要背景執行的function搬出這個method
...
}
public string _ConvertFile(string para1) {
Thread.Sleep(2000); //模擬轉檔時會停頓的時間
return para1;
}
3. 再宣告一個Task,要利用它awaitable的特性,同時利用方便的「Factory.StartNew(...)」來快速的建立與啟動新Task (※也可以不丟參數,直接寫成 "public Task ConverFile()")
public Task ConvertFile(string str)
{
return Task.Factory.StartNew(() => "action");
}
4. 將「步驟2」跟「步驟3」結合
public Task ConvertFile(string str)
{
return Task.Factory.StartNew(() => this._ConvertFile(str+"只是個丟參數的地方"));
}
5. 將組好的task放在method中使用,記得要加上「await」
private async void test_Click(object sender, RoutedEventArgs e){
...
showLog.Text += await ConvertFile("End\r\n"); //取代原本會拖時間的function
...
}
然後就...完成! 可以執行程式,體驗差異了!
【延伸】
有興趣的可以試試看:
1. 只加Async,卻沒用Await,是不是也能成功?
2. 只是把工作丟給Task,卻沒有用Async和Await,是不是也能成功?
如果好奇「await和async」的原理,可以看MSDN的介紹
使用Async 和 Await 設計非同步程式 (C# 和 Visual Basic)
然後找到段落「非同步方法中執行了哪些工作」,會有詳細的執行流程
圖看一次不懂沒關係,不需要刻意去記住,用多就會理解了