2014-10-30 18 views
1

我有DialogViewModel類與async Task LoadData()方法。此方法異步加載數據並顯示此對話框,通知用戶有關加載。下面是代碼:在異步加載對話框視圖模型中捕獲異常

try 
{ 
    var dialog = new DialogViewModel(); 
    var loadTask = dialog.LoadData(); 
    WindowManager.ShowDialog(dialog); 
    await loadTask; 
} 
catch (Exception ex) 
{ 
    Logger.Error("Error in DialogViewModel", ex); 
    // Notify user about the error 
} 

LoadData拋出一個異常,它不被處理,直到用戶退出對話框。發生這種情況是因爲在調用await時處理異常,直到WindowManager.ShowDialog(dialog)完成纔會發生異常。

顯示異步加載對話框的正確方法是什麼?我試過這種方式:

  1. 致電LoadData()OnShow(),構造函數或類似的。但是如果我需要在沒有任何數據的情況下顯示這個對話框,這將不起作用。
  2. 在顯示對話框之前調用await LoadData()。這樣用戶不得不等待數據加載才能真正看到窗口,但我希望窗口立即顯示加載指示符。
+0

http://stackoverflow.com/questions/13239306/how-to-continue-executing-code-after-calling-showdialog – 2014-10-30 15:09:43

+0

不幸的是,這個問題的答案不適合我。我已經寫過關於'Show()'的內容。我想需要從外部調用'LoadData()',因爲只有調用者決定是否加載數據。 至於'BackgroundWorker' - 我希望有一種方法可以做到這一點與異步等待... – STiLeTT 2014-10-30 15:38:11

+0

'WindowManager.ShowDialog()'從哪裏來?它是Caliburn Micro嗎? – svick 2014-10-31 15:36:26

回答

0

爲什麼有明確的公開LoadData方法?

如果發生這種情況,請在構造函數中異步使用Task<T>ContinueWith來處理通過檢查返回的任務上的IsFaulted屬性生成的任何異常。

這將解決您突出顯示的兩個問題。

一個非常簡單的例子如下所示,顯然你的實現將會更加複雜。

public class DialogViewModel 
{ 
    private Task _task; 

    public DialogViewModel() 
    { 
     var context = TaskScheduler.FromCurrentSynchronizationContext(); 

     _task = Task.Factory.StartNew(() => 
      { 
       var data = GetDataCollection(); 
       return data; 
      }) 
      .ContinueWith(t => 
      { 
       if (t.IsFaulted) 
       { 
        HasErrored = true; 
        ErrorMessage = "It's borked!"; 
       } 
       else 
       { 
        Data = t.Result; 
       } 
      }, context); 
    } 

    public IEnumerable<string> Data { get; private set; } 

    public bool HasErrored { get; private set; } 

    public string ErrorMessage { get; private set; } 

    private static IEnumerable<string> GetDataCollection() 
    { 
     return new List<string>() 
     { 
      "John", 
      "Jack", 
      "Steve" 
     }; 
    } 
} 

或者,如果你不想使用Task<T>明確,並希望使用異步\等待你可以使用一個稍微不同的方法,因爲你不能使用異步\等待着一個類的構造函數功能:

public class DialogViewModel 
{ 
    public IEnumerable<string> Data { get; private set; } 

    public bool HasErrored { get; private set; } 

    public string ErrorMessage { get; private set; } 

    async public static Task<DialogViewModel> BuildViewModelAsync() 
    { 
     try 
     { 
      var data = await GetDataCollection(); 
      return new DialogViewModel(data); 
     } 
     catch (Exception) 
     { 
      return new DialogViewModel("Failed!"); 
     } 
    } 

    private DialogViewModel(IEnumerable<string> data) 
    { 
     Data = data; 
    } 

    private DialogViewModel(string errorMessage) 
    { 
     HasErrored = true; 
     ErrorMessage = errorMessage; 
    } 

    private async static Task<IEnumerable<string>> GetDataCollection() 
    { 
     // do something async... 
     return await Task.Factory.StartNew(() => new List<string>() 
     { 
      "John", 
      "Jack", 
      "Steve" 
     }); 
    } 
} 
+0

但是'LoadData()'總是被調用,但我可能想顯示這個對話框而不加載任何數據(正如我在第一種情況中所描述的那樣)。 – STiLeTT 2014-10-30 16:14:07

+0

好吧,這是我認爲你有一個問題的地方,要麼它應該永遠被調用,要麼永遠不會被調用。因爲否則它應該被稱爲不明顯 – AwkwardCoder 2014-10-30 16:16:20