Исключения проглочены в моем приложении WPF. Как заставить приложение аварийно завершить работу? - PullRequest
2 голосов
/ 31 января 2010

Я новичок в WPF, использую VS2010 beta2, .NET 4.0.

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 выполняется как часть привязки данных, и я не уверен, является ли это хорошей практикой (этот конструктор содержит код, который может дать сбой - например, если база данных недоступна).

Ответы [ 5 ]

1 голос
/ 01 марта 2010

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

0 голосов
/ 14 октября 2010

.Net 4.0 \ WPF представляет способ сделать это, см. ответ здесь

0 голосов
/ 31 января 2010

Я уверен, что плохо спроектированное приложение, использующее .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 голосов
/ 01 марта 2010

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

Я добился правильного поведения, переместив код, который может дать сбой (например, вызов доступа к базе данных), из (привязанного к данным) свойства get в конструктор 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 голосов
/ 31 января 2010

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

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

{Binding Age, ValidatesOnDataErrors=true}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...