2012-01-23 3 views
3

У нас есть несколько модулей в нашем приложении. У меня есть проект с группой пользовательских элементов управления, которые используются в модулях. Обратите внимание, что эти пользовательские элементы управления не вводятся в модули, а используются как пользовательский cotrol в встроенной XAML.Стратегия обработки исключений в приложении призмы

Теперь пользовательские элементы управления могут создавать исключения при загрузке. Я хотел бы обрабатывать исключения на уровне модуля. Идея заключается в том, что у меня есть eventaggregator, введенный в конструктор модуля, и после обнаружения исключения я могу запустить событие ошибки.

Например MainView модуля заключается в следующем

XAML

<inf:DockBase 
    x:Class="MainView" 
    xmlns:inf="clr-namespace:Infrastructure" 
    xmlns:usercontrols="clr-namespace:UserControls;assembly=Myusercontrollib"> 

    <Grid> 
     <!--some code here--> 
     <usercontrols:CustomListControl source={Binding myList}/> 
    </Grid> 
</inf:DockBase> 

код за

public MainView()   
{ 
    InitializeComponent();   
} 

public MainView(MainViewViewModel viewmodel, IEventAggregator eventAggregator) 
    :this() 
{ 
    _eventAggregator = eventAggregator; 
} 

Где я могу поймать excpetions из пользовательского элемента управления в уровень модуля?

ответ

6

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

Как только приложение запустилось, если вы хотите обрабатывать необработанные исключения в потоке пользовательского интерфейса без сбоя приложения, вы можете попробовать Application.UnhandledException event. Это позволяет обрабатывать исключение в Silverlight или WPF и обрабатывать его, затем либо отменить, либо продолжить, чтобы исключение выкидывало вас из приложения.

Отказ от ответственности: Все непроверенный код, как в компиляции и выполнения

public class MyView : UserControl 
{ 
    public MyView() 
    { 
     // Hardly best practice, but it'll work 
     try 
     { 
      InitializeComponent(); 
     } 
     catch(Exception caught) 
     { 
      EventAggregatorService.Instance.GetEvent<XamlExceptionEvent>().Publish(/* ... */); 
     } 
    } 
} 

public class EventAggregatorService 
{ 
    public IEventAggregator Instance { get { return _instance; } } 

    // NOTE: Must be called once in your bootstrapper to set the EA instance 
    public static void SetEventAggregator(IEventAggregator instance) 
    { 
     _instance = instance; 
    } 
} 

Принимая это шаг вперед, если вы можете создать базу ViewModel как этот

// Base viewmodel type to handle errors 
public abstract class ErrorViewModel 
{ 
    private IEventAggregator eventAggregator; 
    protected ErrorViewModel(IEventAggregator eventAggregator) 
    { 
     _eventAggregator = eventAggregator; 
    } 

    public void HandleInitializationException(object view, Exception caught) 
    { 
     // Publish event via _eventAggregator 
    } 
} 

Где производном вид модели определены следующим образом:

// Derived viewmodel type 
public class DerivedViewModel : ErrorViewModel 
{ 
    public DerivedViewModel (IEventAggregator eventAggregator) : base(eventAggregator) 
    { 
    } 
} 

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

public class MyView : UserControl 
{ 
    private readonly Exception _ex; 

    public MyView() 
    { 
     try { InitializeComponent(); } catch (Exception caught) { _ex = caught; } 
    } 

    protected override OnDataContextChanged(object sender, EventArgs e) 
    { 
     if (_ex == null) return; 

     var vm = view.DataContext as ErrorViewModel; 
     if (vm != null) 
     { 
      vm.HandleInitializationException(view, caught); 
      return; 
     } 

     throw new Exception("Error occurred during View initialization", _ex); 
    } 
} 

ОК, это не очень аккуратно и не очень красиво, но опять же это сработает. Сделав еще один шаг, вы можете создать тип базового вида, чтобы также исключить инициализацию, однако если вы наследуете несколько разных базовых типов, это не поможет вам. Альтернативно, класс справки откладывает инициализацию, вызывая метод Initializecomponent() посредством отражения.

Наконец, код для обработки UnhandledException:

public partial class App : Application 
{ 
    public App() 
    { 
     this.UnhandledException += this.Application_UnhandledException; 

     InitializeComponent(); 
    } 

    private void Application_UnhandledException(object sender, 
     ApplicationUnhandledExceptionEventArgs e) 
    { 
     if (e.ExceptionObject is FileNotFoundException) 
     { 
      // Inform the user 
      EventAggregatorService.Instance.GetEvent<MyUnhandledExceptionEvent>().Publish(/* ... */); 
      // Recover from the error 
      e.Handled = true; 
      return; 
    } 
} 

Просто некоторые идеи. Мне было бы интересно услышать, есть ли дефакто решение, так как я часто сталкивался с этой проблемой!

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

+0

Я могу видеть это решение будет работать, когда пользовательский элемент управления загружается в первый раз (InitializeComponent()). Тем не менее, пользовательский элемент управления может быть изменен действием пользователя после его успешной загрузки и, следовательно, приведет к исключению. Я изо всех сил пытаюсь выяснить, как эта ситуация может быть решена. Я думаю с точки зрения обработчика исключений, который позаботится об определенных исключениях из внутреннего объекта. Однако я не вижу никакой возможности сделать это в этой ситуации. – Jimmy

+0

@Jimmy вы считали событие Application.UnhandledException? –

+0

Andrew, Application.UnhandledException может решить проблему, но она выглядит немного неправильной для модульного подхода. Кроме того, если я воспринял событие, он поймает необработанные исключения из других модулей в приложении? – Jimmy

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