Захват основного потока SynchronizationContext или Dispatcher из библиотеки

У меня есть библиотека C#, которая хотела бы иметь возможность отправлять/отправлять работу в «основной» поток пользовательского интерфейса (если он существует). Эта библиотека может использоваться:

  • Приложением winforms
  • Нативным приложением (с пользовательским интерфейсом)
  • Консольным приложением (без пользовательского интерфейса)

В библиотеке я хочу что-то захватить (контекст синхронизации). , Dispatcher, Task Scheduler или что-то еще) во время инициализации, что позволит мне (позже) отправлять/отправлять работу в основной поток (если основной поток имеет такую ​​возможность, т. е. у него есть перекачка сообщений). ). Например, библиотека хотела бы разместить некоторый пользовательский интерфейс Winforms в основном потоке тогда и только тогда, когда основное приложение имеет возможность получить доступ к основному потоку.

Что я пробовал:

  1. A SynchronizationContext: Захват этого прекрасно работает для приложения Winforms (WindowsFormsSynchronizationContextбудет установлен как CurrentSynchronizationContext. Это также отлично работает для консольного приложения, поскольку я могу определить, что Current SynchronizationContext null (и, следовательно, знайте, что у меня нет возможности отправлять/отправлять работу в основной поток). Проблема здесь заключается в родном приложении пользовательского интерфейса: у него есть возможность (т.е. у него есть насос сообщений), но текущий Контекст синхронизации нулевой, поэтому я не могу отличить его от случая с консольным приложением. Если бы я мог отличить, я мог бы просто установить WindowsFormsSynchronizationContext в основной поток, и все готово.
  2. A Dispatcher: захват этого с помощью Currentсоздает новый SynchronizationContext.Таким образом, во всех ситуациях я получу назад Dispatcher. Однако для консольного приложения использование Dispatcher.Invokeиз фонового потока приведет к зависанию (как и ожидалось). Я мог бы использоватьDispatcher.FromThread(который не создает Dispatcher для потока, если он не существует). Но собственное приложение пользовательского интерфейса вернет нулевой диспетчер, используя этот метод, и поэтому я снова застрял, не имея возможности отличить приложение пользовательского интерфейса от консольного приложения.
  3. A TaskScheduler: я мог бы использовать FromCurrentSynchronizationContext. Это имеет те же проблемы, что и SynchronizationContext. т.е. Перед вызовом FromCurrentSyncronizationContext мне нужно проверить, является ли Current SynchronizationContext нулевым (что будет иметь место для консольного приложения и собственного приложения пользовательского интерфейса). Итак, я снова не могу отличить собственное приложение пользовательского интерфейса от консольного приложения.

Я, конечно, мог бы попросить пользователя моей библиотеки указать, является ли он приложением с пользовательским интерфейсом, при вызове моего метода Initialize, но я надеялся избежать этого осложнения для пользователя библиотеки. библиотека, если можно.

9
задан Matt Smith 11 June 2012 в 15:04
поделиться