Что такое поток пользовательского интерфейса? В приложении .NET есть только один поток пользовательского интерфейса?
Каково определение потока пользовательского интерфейса? В приложении .NET есть только один поток пользовательского интерфейса?
Ответы (3)
(Упрощение вперед)
Поток пользовательского интерфейса — это поток Single Threading Apartment, который используется для создания различных объектов пользовательского интерфейса (в Winforms это означает элементы управления). По соглашению и правилу доступ к элементу управления может быть только из потока, который использовался для его создания; в противном случае могут и будут получены неожиданные результаты, от визуальных странностей вплоть до аварии.
Если вы явно не создадите больше, в приложении Windows Forms будет только один поток пользовательского интерфейса. Хотя вы можете создать другой поток и запустить цикл обработки сообщений, существует очень мало причин, по которым вы хотели бы это сделать, и два разных потока пользовательского интерфейса не могут «общаться» друг с другом больше, чем любой другой. поток может общаться с потоком пользовательского интерфейса.
Поток пользовательского интерфейса имеет ряд характеристик, которые делают его особенным:
- В Windows есть очередь сообщений, связанная с потоком. Это происходит, как только в потоке создается самое первое окно.
- Поток запускает цикл обработки сообщений, позволяя Windows отправлять сообщения окнам. Цикл сообщений создается, как только вы вызываете Application.Run().
- COM был инициализирован в потоке, запросив однопоточное подразделение. STA необходима, чтобы обеспечить правильную работу многих функций Windows, функций, которые изначально не являются потокобезопасными. COM гарантирует, что эти функции всегда вызываются потокобезопасным способом, направляя вызов из рабочего потока в поток STA по мере необходимости. Примерами этих функций являются Drag+Drop, буфер обмена, диалоговые окна оболочки (OpenFileDialog и т. д.), элементы управления ActiveX, такие как WebBrowser, перехватчики окон, установленные SetWindowsHookEx, поставщики специальных возможностей, такие как используемые программой чтения с экрана, поставщики автоматизации пользовательского интерфейса. Весь внешний код, ни один из них не является потокобезопасным.
- Поток никогда не блокируется ни при каких операциях, он остается отзывчивым, поэтому он может отправлять сообщения Windows по мере необходимости, чтобы поддерживать отзывчивость пользовательского интерфейса и поток запросов маршалинга COM. Например, вызовы WaitHandle.WaitAny() явно запрещены и генерируют исключение. CLR имеет особую поддержку функций WaitOne() и
lock
, запуская внутренний цикл обработки сообщений во избежание взаимоблокировок.
Поток запуска процесса почти всегда выбирается как поток пользовательского интерфейса, хотя это не является жестким требованием. Состояние STA выбирается атрибутом [STAThread] в методе Main().
Вы можете создать поток пользовательского интерфейса, убедившись, что вышеуказанные требования выполнены. Это может выглядеть так в приложении Winforms:
var ui = new Thread(() => { Application.Run(new Form2()); });
ui.SetApartmentState(ApartmentState.STA);
ui.Start();
Это создает второе окно, работающее в собственном потоке пользовательского интерфейса. Одна типичная проблема, с которой вы сталкиваетесь при таком расположении, заключается в том, что теперь у вас есть два отдельных окна, они вообще не связаны друг с другом. 2-е окно не может принадлежать 1-му, оно имеет свой Z-порядок, независимый от 1-го. Трудно справиться с пользователем. Событие SystemEvents.UserPreferenceChanged примечательно тем, что оно неизбежно запускает свое событие в неправильном потоке, что может привести к взаимоблокировке. Многие элементы управления WinForms подписываются на него. За исключением редких случаев, таких как заставка, это совсем не улучшает пользовательский интерфейс.
ОТРЕДАКТИРОВАНО для правильности:
Существует один поток пользовательского интерфейса для каждого активного ПРИЛОЖЕНИЯ в Windows Forms и аналогичная концепция для WPF.
то есть: когда вы запускаете приложение, есть один поток, он становится потоком пользовательского интерфейса, когда Application.Run(new Form1()); называется.
Если вы попытаетесь выполнить Application.Run(new Form2()); во время выполнения вы получите «System.InvalidOperationException: запуск второго цикла сообщений в одном потоке не является допустимой операцией. Вместо этого используйте Form.ShowDialog».
Если вам действительно нужны две отдельные формы, чтобы не использовать один и тот же поток, вам нужно будет создать новый поток, а затем вызвать Application.Run(new MyForm()) и т.д. и т.д. Это не распространено.