的UI可以使用IProgress
或BackgroundWorker.ReportProgress
傳遞從異步任務的信息:Control.Invoke()與IProgress/ReportProgress
class Approach1 : UserControl
{
enum Stage { INIT, STATUS, DATA, TIME, ... }
struct ProgressObject
{
int StatusCode;
int SecondsRemaining;
IList<int> Data;
Stage CurrentStage;
}
TextBox Status;
async Task DoWork1(IProgress<ProgressObject> progress)
{
await Task.Run(() =>
{
progress.Report(new ProgressObject(0, 0, null, Stage.INIT));
int code = DoSomething();
progress.Report(new ProgressObject(code, 0, null, Stage.STATUS));
IList<int> Data = ...;
progress.Report(new ProgressObject(0, 0, Data, Stage.DATA));
int Seconds = ...;
progress.Report(new ProgressObject(0, time, null, Stage.TIME));
});
}
void ReportProgress(ProgressObject progress)
{
switch (progress.CurrentStage)
{
case Stage.CODE:
Status.Text = DecodeStatus(progress.StatusCode);
break;
// And so forth...
}
}
async void Caller1(object sender, EventArgs e)
{
var progress = new Progress<ProgressObject>(ReportProgress);
await DoWork2(progress);
}
}
然而,這也可以通過使一個委託的UI對象的BeginInvoke
完成方法(如果我們想阻止Invoke
):
class Approach2 : UserControl
{
Textbox Status;
int StatusCode
{
set
{
BeginInvoke(new Action(() => Status.Text = DecodeStatus(value));
}
}
// Imagine several other properties/methods like the above:
int SecondsRemaining;
void UpdateData(IList<int> data);
async Task DoWork2()
{
await Task.Run(() =>
{
StatusCode = DoSomething();
UpdateData(...);
SecondsRemaining = ...;
});
}
async void Caller2(object sender, EventArgs e)
{
await DoWork1();
}
}
應的專用進展報告機制優於Invoke
?如果,那爲什麼?兩種方法都有可能出現「陷阱」嗎?
恕我直言,在Invoke
方式相比,比方說簡單/需要更少的代碼,ReportProgress
接受進步結構與幾個領域,特別是如果進展是在任務和報告方法因此需要跳轉到的多個階段報告針對特定階段的適當報告。
「問題代碼」與BeginInvoke vs Task.Run無關,因爲它們都服務於相同的目的。你可能寫了:'BeginInvoke(new Action(()=> progress.Report(value));'得到一個更公平的比較 - 在第一個例子中'做的事'在其他地方完成 – user2864740
我想你誤會了 - 問題是關於使用'Invoke'與框架的專用進度報告功能。在一個情況下,調用上下文使用'Invoke'進行訪問,另一個則由'IProgress'實現隱式捕獲,兩個示例都使用'Task .Run' –
請使代碼保持一致,除非它應該有所不同。因爲任務可以在沒有ReportProgress/IProgress(「更多代碼」)的情況下完成,或者可以使用它完成Invoke。 – user2864740