2014-10-30 1 views
1

async Task LoadData() 메서드를 사용하는 DialogViewModel 클래스가 있습니다. 이 메서드는 데이터를 비동기 적으로로드하고 사용자에게로드를 알리는이 대화 상자를 표시합니다. 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 
} 

,이 처리되지 않은 : 여기에 코드입니다. await을 호출 할 때 예외가 처리되고 WindowManager.ShowDialog(dialog)이 완료 될 때까지 발생하지 않기 때문에 발생합니다.

비동기 로딩 대화 상자를 표시하는 올바른 방법은 무엇입니까? OnShow(), 생성자 또는 유사한에서

  1. 전화 LoadData() :이 방법을 시도했습니다. 그러나이 대화 상자를 데이터없이 표시해야하는 경우에는 작동하지 않습니다.
  2. 대화 상자를 표시하기 전에 await LoadData()으로 전화하십시오. 이렇게하면 사용자는 실제로 창을보기 전에 데이터가로드 될 때까지 기다려야하지만 창을로드 표시기로 즉시 표시하려고합니다.
+0

http://stackoverflow.com/questions/13239306/how-to-continue-executing-code-after-calling-showdialog –

+0

불행히도이 질문의 대답은 저에게 적합하지 않습니다. 나는'Show()'에 대해 이미 썼다. 호출자 만 데이터를로드할지 여부를 결정하기 때문에 외부에서 'LoadData()'를 호출해야합니다. 'BackgroundWorker'에 대해서는 async-await를 사용하여이 작업을 수행 할 수있는 방법이 있기를 희망합니다 ... – STiLeTT

+0

'WindowManager.ShowDialog()'는 어디에서 왔습니까? Caliburn Micro입니까? – svick

답변

0

명시 적 공개 LoadData 방법이있는 이유는 무엇입니까?

이 발생하는 경우 비동기 적으로 반환 작업에 IsFaulted 속성을 선택하여 생성 된 예외를 처리하는 ContinueWithTask<T>를 사용하여 생성자 내에서 그것을 할.

이렇게하면 강조 표시된 두 가지 문제를 해결할 수 있습니다.

매우 간단한 예가 아래에 나와 있으며, obivously 구현이 더 복잡해집니다.

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>를 사용하고 사용하고자하지 않으려면 비동기 \ await를 당신이 클래스 생성자와 비동기 \ await를 사용할 수 없기 때문에 약간 다른 접근 방식을 사용할 수있는 기능 :

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

+0

글쎄, 여기는 당신이 문제가 있다고 생각합니다. 항상 호출되어야하거나 결코 호출되어서는 안됩니다. 그렇지 않으면 호출해야 할 때 명확하지 않기 때문에 ... – AwkwardCoder