2010-01-31 6 views
2

Я новичок в WPF, я использую VS2010 beta2, .NET 4.0.Исключения проглатываются в моем приложении WPF. Как заставить приложение рухнуть?

Throw new Exception("test") в моем коде просто проглатывает исключение и приложение не падает.

Это не то, что я ожидаю, я хочу, чтобы приложение вышло из строя, если произошло необработанное исключение.

Есть ли простой способ достичь этого?

Также не выполнено ни Application.DispatcherUnhandledException, ни AppDomain.UnhandledException. Вероятно, потому, что весь код выполняется как часть привязки данных (я использую шаблон MVVM, а исключение выбрано в конструкторе ViewModel).

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

Edit:

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

Упрощенный пример:

XAML:

<DataTemplate DataType="{x:Type vm:ItemViewModel}"> 
    <vw:ItemControl /> 
</DataTemplate> 

<ContentControl 
Content="{Binding Path=MyItem}"  
/> 

где MyItem создает и возвращает экземпляр ItemViewModel. Проблема в том, что конструктор ItemViewModel выполняется как часть привязки данных, и я не уверен, что это хорошая практика (этот конструктор содержит код, который может быть неудачным - например, если база данных недоступна).

+0

Похожего вопрос: http://stackoverflow.com/questions/1542622/handle-exceptions-with-wpf-and-mvvm но нет ответа :-( –

ответ

1

Вы можете поймать исключения, поднятые во время переплета и реконструировать их - см. the answer to this question.

+0

Спасибо. Это более или менее то, что я сделал с BackgroundWorker, но это прямое решение этой проблемы без асинхронного вызова. –

0

Ответы на вопросы here и here. Они также объясняют, как лучше отлаживать исключения. Однако нет ответов на то, как превратить их в необработанные исключения.

Редактировать: Вы можете проинструктировать привязки, чтобы сигнализировать об ошибке при обновлении источника привязки. См. here. Затем вы можете использовать ErrorTemplate (или использовать по умолчанию), чтобы показать ошибку в пользовательском интерфейсе.

{Binding Age, ValidatesOnDataErrors=true} 
+0

Спасибо. Я прочитал это. К сожалению, я не смог найти способ заставить приложение сбой. :-( –

+0

Вы действительно хотите это сделать? Исключения в привязках могут происходить чаще и более естественно, тогда вы ожидаете. См. пример {Binding Name.Length} из http://stackoverflow.com/questions/2075289/why-does-wpf-swallow-databinding-exceptions/2075385#2075385 –

+0

В этом случае вы можете захотеть изменить ваше название и вопрос, чтобы было более ясно, что вы не заботитесь о том, почему. –

-1

Я уверен, что плохо разработанное приложение с использованием .NET 4 может злоупотреблять AppDomain.FirstChanceException для этой цели.

Журнал сборки дает вам все, что вам нужно знать для поиска проблем в приложении WPF. Вот что было зарегистрировано, когда я бросил в какой-то код, который я знал, пользовательский интерфейс с NotImplementedException был обязан:

System.Windows.Data Error: 17 : Cannot get 'ExitCommand' value (type 'RelayCommand') from '' (type 'ControlCenter'). BindingExpression:Path=ExitCommand; DataItem='ControlCenter' (Name='controlCenterWindow'); target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NotImplementedException: The method or operation is not implemented. 
    at Tvl.Client.ControlCenter.get_ExitCommand() in C:\dev\Tvl\Client\ControlCenter.xaml.cs:line 25 
    --- End of inner exception stack trace --- 
    at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) 
    at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner) 
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) 
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
    at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index) 
    at MS.Internal.Data.PropertyPathWorker.GetValue(Object item, Int32 level) 
    at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)' 
+0

Я хочу, чтобы мое приложение было хорошо спроектировано ;-) –

+0

@pozi: Положите журнал на использование (см. Мое обновление). Оттуда вы можете использовать точки останова или настроить Visual Studio на разрыв, когда выбрано исключение определенного типа (Debug> Exceptions ...). –

+0

Это определенно помогает мне развиваться. Но что делать, если исключение возникает после выхода приложения. Стандартное поведение будет выполняться обработчиком исключений и отправлять данные об ошибках автору (и говорить что-то удобное для пользователя), не игнорируя исключение. (Моя ситуация заключалась в том, что мое приложение отлично работало в (F5) и рушилось (CTRL + F5). Я не мог ничего увидеть в журнале.) –

0

отвечу на мой вопрос сам:

Я достиг правильного поведения путем перемещения кода, который может выйти из строя (например, вызов доступа к базе данных) из getter свойства (data bound) для конструктора View-Model. Кроме того, я использовал BackgroundWorker для этого вызова, поэтому код выполняется асинхронно.Я редуцирую возможное исключение в RunWorkerCompleted - BackgroundWorker гарантирует, что это будет сделано в потоке пользовательского интерфейса.

public TestViewModel() 
{ 
    BackgroundWorker bckgWorker = new BackgroundWorker(); 
    bckgWorker.DoWork += ((s, e) => this.TestExecuteCode());    
    bckgWorker.RunWorkerCompleted += ((s, e) => 
    { 
     if (e.Error != null) 
      throw e.Error; 
    }); 

    bckgWorker.RunWorkerAsync(); 
} 

private void TestExecuteCode() 
{ 
    this.DataBoundProperty = LoadDataFromDb(); 
} 

я сильно предпочитаю этот подход получения данных асинхронно, а не IsAsync = True параметр на связывание в XAML. Этот подход никогда не проглатывает исключения по сравнению с методом IsAsync, когда исключения обрабатываются в потоке рендеринга и по умолчанию проглатываются.

Предупреждение: При запуске этого кода как части модульных тестов обработчик события RunWorkerCompleted по умолчанию не будет привязан к потоку вызывающего абонента. SynchronizationContext, используемый BackgroundWorker, должен быть установлен вручную, чтобы правильно обрабатывать исключения в модульных тестах.

0

.Net 4.0 \ WPF представляет способ сделать это увидеть answer here

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