C # - Можно ли безопасно иметь собственную форму в отдельном потоке? - PullRequest
4 голосов
/ 26 сентября 2010

Я пытаюсь написать специализированную экранную клавиатуру (OSK) для приложения, которое пишу на C #.Чтобы облегчить это, я создал форму, в которой есть несколько кнопок, представляющих клавиши, и щелчок по ним вызывает SendKeys и отправляет соответствующие ключи.

Эта форма принадлежит открытому главному окну.при первом запуске приложения, используя свойство Owner.Таким образом, OSK выскакивает всякий раз, когда пользователь фокусирует приложение, и он остается поверх главного окна, если говорит, что главное окно перетаскивается поверх него.

Это все прекрасно работает, но у меня есть модальные диалогичто я также хочу использовать с OSK, я попытался создать его в отдельном потоке, в комплекте с его собственным циклом сообщений (через Application.Run), чтобы его можно было использовать с любыми модальными диалогами в основном потоке.

Проблема в том, что, очевидно, нахождение в отдельном потоке может вызвать InvalidOperationException s из-за перекрестных вызовов.Один конкретный пример этого - при вызове Application.Run(osk) из нового потока возникает ошибка перекрестного потока, потому что он пытается обновить дескриптор окна с владельцем (главное окно).

Мой вопрос:Возможно ли иметь форму собственности в теме, которая отделена от владельца безопасным способом?И, если это не удастся, возможно ли эмулировать характеристики собственной формы (а именно быть всегда сверху только для основного окна и появляться, когда основное окно сфокусировано)?

Спасибо, и извините, если этосбивает с толку.

Ответы [ 4 ]

1 голос
/ 26 сентября 2010

Я думаю, что это на самом деле ошибка в Windows Forms. Несколько неизбежно из-за способа проверки доступа к свойству Handle не тем потоком. Документы SDK для SetParent не содержат явных указаний, в них говорится, что оба окна принадлежат одному приложению. Нет упоминания о необходимости принадлежать к той же теме. Я точно знаю, что требование к «одному и тому же приложению» не сложно, в Windows есть код для приложения, который делает эту работу для окон из разных процессов. Adobe Acrobat AB / использовал это в течение длительного времени. Что, безусловно, отменяет требование «та же нить».

Ну, решите проблему и попробуйте. Установите для Control.CheckForIllegalCrossThreadCalls значение false до того, как вы установите владельца, затем верните значение true. И проверь это. Если у вас возникли проблемы, попробуйте напрямую вызвать SetParent (), а не устанавливать владельца. Windows Forms фактически использует SetWindowLongPtr, который не рекомендуется SDK.

1 голос
/ 26 сентября 2010

Я сделаю это.Попробуйте запустить OSK как отдельный процесс.

1 голос
/ 26 сентября 2010

Попробуйте также использовать ShowDialog для OSK вместо Application.Run - ShowDialog создает цикл обработки сообщений и завершает его при закрытии окна, и, возможно, решит ваши проблемы.

new Thread(() => new OSK().ShowDialog());
0 голосов
/ 26 сентября 2010

Почему бы не использовать Control.Invoke для выполнения многопоточных вызовов, чтобы избежать InvalidOperationException?

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