Вот мой гипотетический пример. У меня есть очень простое окно WPF с одной Кнопкой. Кнопка. Событие щелчка имеет обработчик, который идет как это.
Action doit = () =>
{
Action error = () => { throw new InvalidOperationException("test"); };
try {
this.Dispatcher.Invoke(error, DispatcherPriority.Normal);
} catch (Exception ex) {
System.Diagnostics.Trace.WriteLine(ex);
throw;
}
};
doit.BeginInvoke(null, null);
Я ожидал бы, что исключение будет поймано и записано Trace.WriteLine
звонить. Вместо этого никакое исключение не поймано и повреждения приложения.
Кто-либо знает о возможном объяснении этого для случая? И что обходное решение, Вы предлагаете для ловли исключений, выданных делегатом, вызванным Dispatcher.Invoke
?
Обновление 1: Я поместил a throw
в коде обработки исключений. Я не хочу на самом деле игнорировать исключение. Смысл моего вопроса должен обработать его правильно. Проблема состоит в том, что код обработки исключений никогда не выполняется.
Помните, что это - гипотетический пример. Мой реальный код не похож на это. Кроме того, предположите, что я не могу изменить код в методе, который будет вызван.
Обновление 2: Рассмотрите этот подобный пример. Вместо окна WPF у меня есть окно Windows Forms. Это имеет кнопку с почти точно тот же обработчик. Единственная разница находится в коде вызова. Это идет как это.
this.Invoke(error);
В Windows Forms выполнен код обработки исключений. Почему различие?
ОБНОВЛЕНО: Чтобы наблюдать исключение в другом потоке, вы хотите использовать задачу
, поставить ее в очередь в поток Dispatcher
(используя TaskScheduler.FromCurrentSynchronizationContext
) и подождите, как таковой:
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Action doit = () =>
{
var error = Task.Factory.StartNew(
() => { throw new InvalidOperationException("test"); },
CancellationToken.None,
TaskCreationOptions.None,
ui);
try {
error.Wait();
} catch (Exception ex) {
System.Diagnostics.Trace.WriteLine(ex);
}
};
doit.BeginInvoke(null, null);
ОБНОВЛЕНО (снова): Поскольку ваша цель - компонент многократного использования, я рекомендую перейти на интерфейс на основе Task
или что-то в этом роде. иначе на основе SynchronizationContext
, такого как асинхронный шаблон на основе событий , вместо того, чтобы базировать компонент на Dispatcher
или ISynchronizeInvoke
.
Компоненты на основе Dispatcher
работают только в WPF / Silverlight; Компоненты на основе ISynchronizeInvoke
работают только в Windows Forms. Компоненты на основе SynchronizationContext
будут работать с WPF или Windows Forms прозрачно и (с немного большей работой) с ASP.NET, консольными приложениями, службами Windows и т. Д.
Асинхронный шаблон на основе событий - это старый рекомендуемый способ написания компонентов на основе SynchronizationContext
; он все еще существует для кода эпохи .NET 3.5. Однако если вы используете .NET 4, параллельная библиотека задач намного более гибкая, чистая и мощная. TaskScheduler.FromCurrentSynchronizationContext
использует SynchronizationContext
внизу и представляет собой новый способ написания повторно используемых компонентов, которые нуждаются в такой синхронизации.