[C#] 非同步呼叫方法並跳出處理中視窗
前言
當我們在Winform進行某些比較花時間的運算時,
若沒有使用非同步的方法來呼叫,畫面上的視窗就會顯示沒有回應,
這是一種比較差的使用者體驗,可能會讓使用者以為當機了,
在這邊為了方便重複使用,所以寫了一個Template Class來當作非同步的呼叫媒介,
也可以同時在非同步處理時,跳出提示訊息顯示"處理中"
實際演練
為了統一非同步的行為,並在處理時顯示同樣的提示視窗,
所以我們撰寫了一個Template Class來處理非同步的邏輯。
public class AsyncTemplate
{
public static Action OnInvokeStarting { get; set; }
public static Action OnInvokeEnding { get; set; }
public static void DoWorkAsync(Action beginAction, Action endAction, Action<Exception> errorAction)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(
(o) =>
{
try
{
beginAction();
endAction();
}
catch (Exception ex)
{
errorAction(ex);
return;
}
finally
{
if (OnInvokeEnding != null)
{
OnInvokeEnding();
}
}
})
, null);
if (OnInvokeStarting != null)
{
OnInvokeStarting();
}
}
public static void DoWorkAsync<TResult>(Func<TResult> beginAction, Action<TResult> endAction, Action<Exception> errorAction)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(
(o) =>
{
TResult result = default(TResult);
try
{
result = beginAction();
endAction(result);
}
catch (Exception ex)
{
errorAction(ex);
return;
}
finally
{
if (OnInvokeEnding != null)
{
OnInvokeEnding();
}
}
})
, null);
if (OnInvokeStarting != null)
{
OnInvokeStarting();
}
}
}
在這邊提供了兩個方法來提供非同步的作業,分別是沒有回傳值以及有回傳值,
然後提供了兩個Action,讓我們可以在處理之前跳出提示視窗,處理完後關閉提示視窗,
在這邊準備了兩個Form,一個Form提供了加法的計算
另外一個Form則顯示處理中,以及一個Progress Bar滾動模擬資料處理
(小技巧:將Progress Bar的Style設為Marquee即可獲得如上圖之效果)
Form1的程式碼如下
public partial class Form1 : Form
{
private Form2 mProgressFrom = new Form2();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
AsyncTemplate.DoWorkAsync(
() =>
{
return doWork(int.Parse(textBox1.Text), int.Parse(textBox2.Text));
},
(result) =>
{
MessageBox.Show("Success, Result is " + result.ToString());
},
(exception) =>
{
MessageBox.Show(exception.Message);
//error handling
});
}
private int doWork(int a, int b)
{
Thread.Sleep(10000);
return a + b;
}
private void Form1_Load(object sender, EventArgs e)
{
AsyncTemplate.OnInvokeStarting =
() =>
{
mProgressFrom.ShowDialog();
};
AsyncTemplate.OnInvokeEnding =
() =>
{
if (mProgressFrom.InvokeRequired)
{
mProgressFrom.Invoke(new MethodInvoker(
()
=>
{
mProgressFrom.Close();
})
);
}
else
{
mProgressFrom.Close();
}
};
}
}
在Form_Load方法中,我們設定了OnInvokeStarting和OnInvokeEnding的屬性,
分別在開始處理時顯示處理中視窗,以及當運算完成時關閉提示視窗。
在doWork方法中,進行的是加法的運算,在這邊為了模擬長時間的運算,
所以我們在此方法中停留了十秒。
而button1_Click方法中使用Template Class來呼叫主要的演算邏輯
實際執行程式,我們可以發現達到了我們預期中的效果,
按下計算時,跳出了提示視窗,讓使用者知道正在進行大量的運算,
也不會呈現沒有回應的狀態。
結語
好的使用者體驗,是非常重要的,
不但可以讓使用者使用更順手,也不會誤認程式常常當機,
在.Net中還有許多種非同步的作法,例如BackgroundWorker,
大家可以按照自己在開發時的需求做改變,
在這邊提供了一種實作的方式,也歡迎大家多多指教與討論 ^^