WinForms: Вопрос реализации для того, чтобы мой пользовательский интерфейс работал независимо от моего слоя BLL? - PullRequest
2 голосов
/ 03 октября 2008

Я пытаюсь создать приложение для 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, но у меня есть крайний срок, и некоторые примеры того, как заставить класс в главном потоке порождать поток, содержащий пользовательский интерфейс, и заставить их объекты взаимодействовать друг с другом, могут действительно помочь.

Ответы [ 2 ]

2 голосов
/ 03 октября 2008

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

0 голосов
/ 03 октября 2008

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

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

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

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