WinForms: вопрос реализации для того, чтобы мой пользовательский интерфейс работал независимо от моего уровня BLL?

Я пытаюсь сделать приложение Windows Forms в стиле MVP и, не особо много занимаясь потоковой передачей, все запутался.

Мой пользовательский интерфейс - это набор очень простых форм. Каждая из форм реализует интерфейс и содержит ссылку на класс-посредник, который находится на уровне бизнес-логики, и наоборот. Итак, упрощенная схема выглядит так:

CheckInForm : ICheckIn                      <-------> CheckInMediator : ICheckInMediator
----------------------------------------------------------------------------------------
CheckInForm.Show()                          <--------
                                            --------> AttemptCheckIn(CheckInInfo)
CheckInForm.DisplayCheckInInfo(DisplayInfo) <-------- 
                                            --------> CompleteCheckIn(AdditionalCheckInInfo)
  PleaseWaitDialog.Show()                   <--------
  PleaseWaitDialog.Close()                  <--------
CheckInForm.Close()                         <--------

Как видите, классы-посредники управляют пользовательским интерфейсом, сообщая ему, когда отображать данные, запускать, закрывать и т. д. Они даже указывают, когда должен появиться модальный диалог и когда он должен закрываться (например, PleaseWaitDialog выше). Пользовательский интерфейс показывает данные на экране и ретранслирует ввод обратно посреднику.

Эта архитектура хороша и изолирована, ее очень легко протестировать и создать прототип. Теперь, когда я собираю все это вместе, я начинаю сталкиваться с проблемами потоковой передачи. Например, если я хочу, чтобы мой PleaseWaitDialog отображался как модальная форма (с использованием ShowDialog ()) поверх CheckInForm, пока таймер, управляемый посредником, не отсчитает 5 секунд (помните, это упрощение), я получу ошибку перекрестной потоковой передачи если я вызываю PleaseWaitDialog.Close () из обратного вызова таймера. Аналогичным образом, если у меня есть модальное диалоговое окно, блокирующее взаимодействие пользователя с пользовательским интерфейсом, я не хочу, чтобы это блокировало активность на бизнес-уровне, если я не укажу иное (например, с диалоговым окном подтверждения).

Я думаю, что хотел бы запустить посредников и бизнес-логику в основном потоке, а пользовательский интерфейс - в совершенно отдельном потоке, и мой первый вопрос: имеет ли это смысл?

Мой второй вопрос: как мне сделать что-то вроде запуска класса в отдельном потоке? И как мне эти двое общаться? Я продолжаю читать о потоках .NET, но у меня есть крайний срок и несколько примеров того, как создать класс в основном потоке, чтобы создать поток, содержащий пользовательский интерфейс, и заставить их объекты разговаривать друг с другом, это действительно может помочь.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
842
2

Ответы 2

Вы изучили класс Справочная информация? Он отлично подходит для выполнения большей части упрощенной обработки в процедурах фонового типа и дает события, которые можно перечислить, чтобы ваш графический интерфейс отображался прогрессом.

Я смотрел на это, но не должен хорошо понимать, как это будет работать в этом случае. Вы можете объяснить дальше?

George Mauer 03.10.2008 17:02

В приведенном выше примере ваш метод DisplayCheckinInfo запускает метод CompleteCheckIn с помощью параметра BackgroundWorker. Таким образом, полная обработка проверки может запускаться в отдельном потоке, а затем вы можете отслеживать ее прогресс и соответствующим образом обновлять диалоговое окно.

Dillie-O 03.10.2008 19:26

Вы может манипулируете элементами управления WinForms из другого потока, но вам нужно использовать Control.Invoke(), и вы будете платить значительную потерю производительности за каждый межпотоковый вызов из-за переключения контекста и связанного за кулисами Voodoo CLR.

Если вы хотите отделить графический интерфейс от бизнес-логики и кода инфраструктуры в многопоточном приложении, я рекомендую переключиться на модель обмена сообщениями с использованием потоковобезопасных очередей. Каждый раз, когда нижнему уровню (-ам) требуется указать графическому интерфейсу пользователя что-то сделать, они помещают объект сообщения в очередь, которую элементы графического интерфейса периодически опрашивают через Forms.Timer. Это особенно хорошо работает для больших приложений с интенсивной загрузкой процессора, потому что вы можете до некоторой степени ограничить потребность в обработке обновлений графического интерфейса пользователя, регулируя частоту таймера обновления.

Для обратных вызовов (GUI → нижние уровни) вы можете просто вызвать методы-посредники из кода GUI, если эти вызовы возвращаются достаточно быстро - вам нужно быть очень осторожным с задержкой потока GUI, потому что пострадает отзывчивость всего приложения. Если у вас есть звонки, на которые сложно ответить достаточно быстро, вы можете добавить вторую очередь в обратном направлении.

Вы знаете какие-нибудь статьи или исходный код, где это делается, чтобы я мог увидеть несколько практических примеров? Честно говоря, это довольно простое приложение, поэтому производительность не является большой проблемой.

George Mauer 03.10.2008 17:24

Другие вопросы по теме