2017-03-17 20 views
0

MVVM Lightを使用していて、ダイアログを表示するために使用するインターフェイスIDialogServiceがあります。このインタフェースは、App.xaml.csに実装されているC#がGUIスレッドで待機して例外をキャッチWPF

一つの具体的な方法は興味深い:_currentTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();OnStartup

に定義されている場合

 public Task<bool> ShowMessage(string message, string title, string buttonConfirmText, 
     string buttonCancelText, 
     Action<bool> afterHideCallback) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      var style = new Style(typeof(MessageBox)); 
      style.Setters.Add(new Setter(MessageBox.OkButtonContentProperty, buttonConfirmText)); 
      style.Setters.Add(new Setter(MessageBox.CancelButtonContentProperty, buttonCancelText)); 
      var result = MessageBox.Show(_GetActiveWindow(), message, title, 
       MessageBoxButton.OKCancel, 
       MessageBoxImage.Question, style) == MessageBoxResult.OK; 
      if (afterHideCallback != null) afterHideCallback(result); 
      return result; 

:として

Task<bool> ShowMessage(string message, string title, string buttonConfirmText, string buttonCancelText, Action<bool> afterHideCallback); 

方法が実装されています

通常、ブール値を取得するには、前に待ってこのメソッドを呼び出す必要があります。

var result = await DialogService.ShowMessage(
         Resources.Areyousure,Resources.Warning, 
         Resources.Yes, Resources.No, null); 

これまでのところとても良いです。今私はコードを実行し、例外をキャッチし、エラーメッセージ付きボックスを表示するラッパーメソッドがあります。

public bool TryCatchExecution(Action action, string successMessage = null) 
    { 
     try 
     { 
      action(); 

      if (!string.IsNullOrEmpty(successMessage)) 
       DialogService.ShowMessage(successMessage, Resources.Success); 
      return true; 
     } 
     catch (LogException ex) 
     { 
      DialogService.ShowError(ex.Error.LogMessage, Resources.Error, Resources.OK, null); 
     } 
     catch (Exception ex) 
     { 
      DialogService.ShowError(ex.Message, Resources.Error, Resources.OK, null); 
     } 
     return false; 
    } 

これで問題が発生しました。サンプルAのように使用すると、GUIスレッドは行var result = DialogService.ShowMessageでブロックされます。しかし、サンプルBのようにGUIスレッドがブロックされていない場合、メッセージボックスが表示され、すべてが正常に動作するように動作します。私が例外を得るまで。例外はコードによって手つかずです。エラーは、 "mscorlib.dllで 'System.ServiceModel.FaultException`1'型の最初のチャンス例外が発生し、アプリケーションがクラッシュします。私が読んでいるように、これにはSynchronizationContextと関連があります。

//Sample A 
    private void ExecuteDeleteCommand() 
    { 
     TryCatchExecution(() => 
      { 
       var result = DialogService.ShowMessage(
        Resources.Areyousure, 
        Resources.Warning, 
        Resources.Yes, 
        Resources.No, null).Result; 
       if (!result) return; 

       _datalayer.DeleteField(FieldSelected); 
       Refresh(); 
       FieldEdit = new MsgSqlFieldMapping(); 
       RaisePropertyChanged("SqlRepository"); 
       DialogService.ShowMessage(Resources.OperationSucceeded, Resources.Success); 
      }); 
    } 

    //Sample B 
    private void ExecuteDeleteCommand() 
    { 
     TryCatchExecution(async() => 
     { 
      var result =await DialogService.ShowMessage(
       Resources.Areyousure, 
       Resources.Warning, 
       Resources.Yes, 
       Resources.No, null); 
      if (!result) return; 

      _datalayer.DeleteField(FieldSelected); 
      Refresh(); 
      FieldEdit = new MsgSqlFieldMapping(); 
      RaisePropertyChanged("SqlRepository"); 
      await DialogService.ShowMessage(Resources.OperationSucceeded, Resources.Success); 
     }); 
    } 

ここで起こっていることと対処方法を理解してください。

THNXたくさん。

+0

私は.net4.5フレームワークを使用していますことを言及するのを忘れています。 – Gintaras

答えて

1

async voidの問題が原因です。具体的には、ラムダをタイプActionの引数として渡すと、async voidメソッドが作成されます。 problems with async void methodsの1つは、例外をキャッチできないことです(少なくとも通常の方法ではない)。

、これを解決するasync equivalent of Action, which is Func<Task>を取り、あなたのヘルパーメソッドのオーバーロードを作成するには:

public async Task<bool> TryCatchExecution(Func<Task> action, string successMessage = null) 
{ 
    try 
    { 
     await action(); 

     if (!string.IsNullOrEmpty(successMessage)) 
      DialogService.ShowMessage(successMessage, Resources.Success); 
     return true; 
    } 
    catch (LogException ex) 
    { 
     DialogService.ShowError(ex.Error.LogMessage, Resources.Error, Resources.OK, null); 
    } 
    catch (Exception ex) 
    { 
     DialogService.ShowError(ex.Message, Resources.Error, Resources.OK, null); 
    } 
    return false; 
} 
+0

こんにちは、ソリューションありがとうございます。小さな問題があります。私はすでにこの解決策を検討していました。問題は、メソッドのシグネチャを変更した後、約200のメソッドを変更する必要があったことです。 – Gintaras

+1

@Gintaras:あなたのメソッドを変更しないでください。これを追加するだけです。 –

関連する問題