Почему исключения не распространены Диспетчером WPF. Вызвать?

Вот мой гипотетический пример. У меня есть очень простое окно 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 выполнен код обработки исключений. Почему различие?

14
задан jpbochi 24 June 2010 в 21:11
поделиться

1 ответ

ОБНОВЛЕНО: Чтобы наблюдать исключение в другом потоке, вы хотите использовать задачу , поставить ее в очередь в поток 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 внизу и представляет собой новый способ написания повторно используемых компонентов, которые нуждаются в такой синхронизации.

6
ответ дан 1 December 2019 в 16:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: