2016-01-11 4 views
0

У меня есть случай, когда исключение, созданное в потоке пользовательского интерфейса, не попадает в вызывающий поток.SynchronizationContext и DispatcherUnhandledException

using System; 
using System.Diagnostics; 
using System.Threading; 
using System.Windows; 

namespace SynchronisationContextAndExceptionWPF 
{ 
    public partial class MainWindow : Window 
    { 
     private readonly SynchronizationContext _synchronizationContext; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      _synchronizationContext = SynchronizationContext.Current; 
     } 


     private void Button_OnClick(object sender, RoutedEventArgs e) 
     { 
      try 
      { 
       _synchronizationContext.Send(
        x => 
        { 
         try 
         { 
          DoSomethingOnUiThreadThatThrowsException(); 
         } 
         catch (Exception) 
         { 
          Debug.WriteLine("Catched Exception in thread that threw it."); 
          throw; 
         } 
        }, null); 
      } 
      catch (Exception) 
      { 
       Debug.WriteLine("Catched Exception in thread that calles Send-Method."); 
       throw; 
      } 
     } 

     private static void DoSomethingOnUiThreadThatThrowsException() 
     { 
      throw new Exception("Any Exception..."); 
     } 
    } 
} 

Сначала я подумал, что не может возможно (вся документация я нашел, сказал, что я могу поймать исключения там). После некоторого повторного поиска я обнаружил проблему: в моем приложении используется UnhandledExceptionHandler. Это обрабатывает DispatcherUnhandledException -Event. Я показываю некоторую информацию для пользователя и установить e.Handled = true;:

using System.Diagnostics; 
using System.Windows; 
using System.Windows.Threading; 

namespace SynchronisationContextAndExceptionWPF 
{ 
    public partial class App : Application 
    { 
     public App() 
     { 
      DispatcherUnhandledException += App_DispatcherUnhandledException; 
     } 

     private static void App_DispatcherUnhandledException(
      object sender, 
      DispatcherUnhandledExceptionEventArgs e) 
     { 
      Debug.WriteLine("Catched Exception in UnhandledExceptionHandler."); 

      // This line makes the difference: 
      e.Handled = true; 
     } 
    } 
} 

Итак, вопрос: почему же DispatcherUnhandledException -Event поднял, даже если я с этим справиться? Как бы вы решили эту ситуацию?

ответ

0

Если у вас есть много элементов управления, вы можете создать новый класс, который remenbers специального переменного исключения. Поэтому вам нужно только изменить инициализацию вашего _synchronizationContext (надеюсь, только один раз в вашем базовом классе ваших элементов управления).

public partial class MainWindow : Window 
{ 
    private readonly MySynchronizationContext _synchronizationContext; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     _synchronizationContext = new MySynchronizationContext(SynchronizationContext.Current); 

    } 

    private void button_Click(object sender, RoutedEventArgs e) 
    { 
     try 
     { 
      _synchronizationContext.Send(
       x => 
       { 
        DoSomethingOnUiThreadThatThrowsException(); 
       }, null); 
     } 
     catch (Exception) 
     { 
      Debug.WriteLine("Catched Exception in thread that calles Send-Method."); 
      throw; 
     } 
    } 

    private static void DoSomethingOnUiThreadThatThrowsException() 
    { 
     throw new Exception("Any Exception..."); 
    } 
} 

class MySynchronizationContext 
{ 
    SynchronizationContext innerContext; 

    public MySynchronizationContext(SynchronizationContext ctx) 
    { 
     innerContext = ctx; 
    } 

    public virtual void Send(SendOrPostCallback d, object state) 
    { 
     Exception threadException = null; 

     try 
     { 
      innerContext.Send(_ => 
      { 
       try 
       { 
        d.Invoke(state); 
       } 
       catch (Exception exception) 
       { 
        threadException = exception; 
       } 
      }, null); 
     } 
     catch (Exception ex) 
     { 

     } 

     if (threadException != null) 
     { 
      throw new Exception("Synchronization error", threadException); 
     } 
    } 
} 
+0

Это работает для меня! Возможно, это не общее решение для всех, но делает меня счастливым прямо сейчас. Благодаря! – joerg

1

Считая код, который у вас есть, он поднят из-за throw в вашем блоке catch. Удалите throw, если вы не хотите передавать исключение другим обработчикам.

+0

Я не думаю, что вы правы поняли мой вопрос ... в «кидают» s только там для ввода отладки сообщений там, чтобы увидеть, где код выполняется, и где не – joerg

0

Внутри выражения лямбда вы можете установить переменную Exception и проверить эту переменную позже в вызывающем потоке. Если он был установлен, то генерируйте исключение при вызове потока.

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Exception threadException = null; 

     try 
     { 
      _synchronizationContext.Send(
       x => 
       { 
        try 
        { 
         DoSomethingOnUiThreadThatThrowsException(); 
        } 
        catch (Exception ex) 
        { 
         Debug.WriteLine("Catched Exception in thread that threw it."); 
         threadException = ex; 
         //throw; --> don't throw exception here; otherwise you will get DispatcherUnhandledException twice. 
        } 
       }, null); 
     } 
     catch (Exception) 
     { 
      Debug.WriteLine("Catched Exception in thread that calles Send-Method."); 
      throw; 
     } 

     if(threadException != null) 
     { 
      Debug.WriteLine("Catched Exception in thread that calles Send-Method."); 
      throw threadException; //throw you previously catched exception here. 
     } 
    } 

С наилучшими пожеланиями, Daniel

+1

уверен, что это будет работать .. но это означает, что я должен помнить, что каждый раз это называю так ... дополнительно: если у меня есть модульное программное обеспечение, где у меня есть элементы управления, которые работают таким образом (и не знают об UnhandledExceptionHandler), они не будут работать должным образом ... – joerg

Смежные вопросы