Как инкапсулировать взаимодействие с пользователем в одном методе
Я использую внешнюю платформу, которая определяет интерфейс с помощью одного метода:
bool Authenticate();
то есть весь процесс аутентификации, включая взаимодействие с пользователем (WinForms). То, что я хотел бы сделать, это что-то вроде:
bool Authenticate()
{
bool succeeded = false;
bool userCancelled = false;
while(!succeeded && !userCancelled)
{
var credentials = AskTheUserForCredentials(); // this needs to wait for user input before returning!
if (credentials == null)
userCancelled = true;
else
succeeded = AuthenticateWithAnExternalServer(credentials);
if (!succeeded)
ShowErrorMessage();
}
return succeeded;
}
Теперь простой способ реализовать AskTheUserForCredentials()
а также ShowErrorMessage()
это использовать Form.ShowDialog()
внутри. Это действительно плохой пользовательский опыт, так как диалоговое окно исчезает для фактического процесса аутентификации, а сообщение об ошибке появляется в новом диалоговом окне, которое нужно щелкнуть, чтобы закрыть.
Я бы предпочел, чтобы все это было в единой форме, которая остается видимой, соответствующим образом отключает текстовые поля / кнопки и сама отображает сообщение об ошибке.
Как бы вы сделали это в этом единственном, блокирующем вызове метода?
ОБНОВИТЬ
Лучшее решение на данный момент - внедрить насос сообщений внутри AskTheUserForCredentials()
:
Credentials AskTheUserForCredentials()
{
while(NeitherOkNorCancelPressed())
{
Application.DoEvents();
Thread.Sleep(10); // Standard Sleep(0) results in 100% procesor core usage.
}
return CreateCredentialsFromTextboxesEtc();
}
Теперь мы все знаем, что насосы сообщений далеко не чисты.
Насколько плохо это решение?
Что-нибудь лучше?
ОБНОВЛЕНИЕ 2
У насоса сообщений были некоторые подводные камни:
быть некрасивым и не полностью эффективным
работает ужасно медленно с White UIAutomation
Я закончил тем, что делегировал весь процесс диалогу как ChrisBD (диалог закрывается только после окончательного успеха или неудачи). Это заняло больше времени, чтобы абстрагировать аутентификацию от графического интерфейса с IoC, но в конечном итоге все чисто и работает как задумано.
1 ответ
Я думаю, что ты почти там.
Отобразите модальное диалоговое окно, которое имеет пользовательские элементы управления вводом, и при необходимости оно вызывает метод Authenticate.
Затем вы можете выбрать, когда диалоговое окно должно закрываться, и действительно, где отображается любое сообщение об ошибке.
Имейте свойство модального диалогового класса, укажите, была ли аутентификация успешной или нет. Когда вы закрываете класс диалога (который был создан вашим основным приложением до того, как он открыл его модально), основное приложение продолжит работу - вы можете проверить, прошла ли аутентификация успешно или нет, проверив соответствующее свойство класса диалога.
*отредактировано здесь *
Если вы сами реализуете метод Authenticate, то именно эта функция вызывает модальное диалоговое окно, а не ваше основное приложение (как указано ранее). Пользовательский класс формы может запускать всю вашу логику аутентификации и отображать ваши элементы управления взаимодействием с пользователем, а также любые сообщения об ошибках. Не забудьте удалить кнопки свертывания и закрытия и установить свойство класса, чтобы указать успешность или неудачу процесса аутентификации.
Вызывающая структура будет ожидать возвращаемого значения вашего метода аутентификации.