У меня есть библиотека C#, которая хотела бы иметь возможность отправлять/отправлять работу в «основной» поток пользовательского интерфейса (если он существует).
Эта библиотека может использоваться:
- Приложением winforms
- Нативным приложением (с пользовательским интерфейсом)
- Консольным приложением (без пользовательского интерфейса)
В библиотеке я хочу что-то захватить (контекст синхронизации). , Dispatcher, Task Scheduler или что-то еще) во время инициализации, что позволит мне (позже) отправлять/отправлять работу в основной поток (если основной поток имеет такую возможность, т. е. у него есть перекачка сообщений). ). Например, библиотека хотела бы разместить некоторый пользовательский интерфейс Winforms в основном потоке тогда и только тогда, когда основное приложение имеет возможность получить доступ к основному потоку.
Что я пробовал:
- A SynchronizationContext:
Захват этого прекрасно работает для приложения Winforms (WindowsFormsSynchronizationContextбудет установлен как CurrentSynchronizationContext. Это также отлично работает для консольного приложения, поскольку я могу определить, что Current SynchronizationContext null (и, следовательно, знайте, что у меня нет возможности отправлять/отправлять работу в основной поток). Проблема здесь заключается в родном приложении пользовательского интерфейса: у него есть возможность (т.е. у него есть насос сообщений), но текущий Контекст синхронизации нулевой, поэтому я не могу отличить его от случая с консольным приложением. Если бы я мог отличить, я мог бы просто установить WindowsFormsSynchronizationContext в основной поток, и все готово.
- A Dispatcher: захват этого с помощью Currentсоздает новый SynchronizationContext.Таким образом, во всех ситуациях я получу назад Dispatcher. Однако для консольного приложения использование
Dispatcher.Invoke
из фонового потока приведет к зависанию (как и ожидалось). Я мог бы использоватьDispatcher.FromThread
(который не создает Dispatcher для потока, если он не существует). Но собственное приложение пользовательского интерфейса вернет нулевой диспетчер, используя этот метод, и поэтому я снова застрял, не имея возможности отличить приложение пользовательского интерфейса от консольного приложения.
- A TaskScheduler: я мог бы использовать FromCurrentSynchronizationContext. Это имеет те же проблемы, что и SynchronizationContext. т.е. Перед вызовом FromCurrentSyncronizationContext мне нужно проверить, является ли Current SynchronizationContext нулевым (что будет иметь место для консольного приложения и собственного приложения пользовательского интерфейса). Итак, я снова не могу отличить собственное приложение пользовательского интерфейса от консольного приложения.
Я, конечно, мог бы попросить пользователя моей библиотеки указать, является ли он приложением с пользовательским интерфейсом, при вызове моего метода Initialize
, но я надеялся избежать этого осложнения для пользователя библиотеки. библиотека, если можно.
задан Matt Smith 11 June 2012 в 15:04
поделиться