MVP навигация в WinForms
Изучали MVP и пытались написать тестовое приложение, используя его в WinForms. Я изо всех сил пытаюсь найти хорошо объясненный пример того, как перемещаться между моими формами/представлениями. В качестве примера, программа запускается, и я хочу показать диалоговое окно входа, а затем перейти в мой основной вид, если вход был успешным. На данный момент мой основной метод выглядит примерно так:
static void Main()
{
var loginView = Injector.Resolve<ILoginView>();
if (loginView.DoLogin() != LoginResult.OK) return;
var mainView = Injector.Resolve<IMainView>();
Application.Run(mainView); // won't work as mainView isn't a form
}
Объект инжектора - это просто оболочка вокруг инструмента IoC (в настоящее время StructureMap). Дело в том, что я читал, что я ... на самом деле не следует вручную создавать экземпляры с помощью инжектора, поскольку они действительно должны быть сделаны с помощью инъекции конструктора.
Мне удалось сделать это до определенного момента, но не тогда, когда дело доходит до навигации. Я не могу придумать элегантный способ перемещения по своим взглядам, и мне интересно, может ли кто-нибудь здесь пролить свет на это? Я немного читал о контроллерах приложений, но не нашел примера, чтобы показать это ясно.
3 ответа:
Что касается навигационного вопроса:
Мне удалось сделать это до определенного момента, но не тогда, когда дело доходит до навигация. Я не могу придумать элегантный способ продвижения через мои взгляды и задавался вопросом, Может ли кто-нибудь здесь пролить свет на это? Я почитал немного о контроллерах приложений но не нашел примера чтобы показать это ясно.
Ниже приведена упрощенная версия конструкции, которую я использовал. Обратите внимание, что установку и демонтаж крючки называются автоматически при вызове метода
NavigateTo
. Кроме того, +1 к @AlexBurtsev, поскольку его ответ намекает на этот самый подход.// Presenter can and should offer common services for the // subclasses abstract class Presenter { public void Display() { OnDisplay(); } public void Dismiss() { OnDismiss(); } protected virtual OnDisplay() // hook for subclass { } protected virtual OnDismiss() // hook for subclass { } private NavigationManager _navMgr; internal NavigationMgr NavigationManager { get { return _navMgr; } set { _navMgr = value; } } } // NavigationManager is used to transition (or navigate) // between views class NavigationManager { Presenter _current; // use this override if your Presenter are non-persistent (transient) public void NavigateTo(Type nextPresenterType, object args) { Presenter nextPresenter = Activator.CreateInstance(nextPresenterType); NavigateTo(nextPresenter); } // use this override if your Presenter are persistent (long-lived) public void NavigateTo(Presenter nextPresenter, object args) { if (_current != null) { _current.Dismiss() _current.NavigationMgr = null; _current = null; } if (nextPresenter != null) { _current = nextPresenter; _current.NavigationMgr = this; _current.Display(args); } } } class MainMenuPresenter : Presenter { private IMainMenuView _mainMenuView = null; // OnDisplay is your startup hook protected override void OnDisplay() { // get your view from where ever (injection, etc) _mainMenuView = GetView(); // configure your view _mainMenuView.Title = GetMainTitleInCurrentLanguage(); // etc // etc // listen for relevent events from the view _mainMenuView.NewWorkOrderSelected += new EventHandler(MainMenuView_NewWorkOrderSelected); // display to the user _mainMenuView.Show(); } protected override void OnDismiss() { // cleanup _mainMenuView.NewWorkOrderSelected -= new EventHandler(MainMenuView_NewWorkOrderSelected); _mainMenuView.Close(); _mainMenuView = null; } // respond to the various view events private void MainMenuView_NewWorkOrderSelected(object src, EventArgs e) { // example of transitioning to a new view here... NavigationMgr.NavigateTo(NewWorkOrderPresenter, null); } } class NewWorkOrderPresenter : Presenter { protected override void OnDisplay() { // get the view, configure it, listen for its events, and show it } protected override void OnDismiss() { // unlisten for events and release the view } }
Я уже давно не использую WinForms, но постараюсь ответить на этот вопрос. Я бы использовал ту же стратегию, что и WPF Prism.
О MainView и приложении.Бежать: Создайте основную область (корневую форму), с пустым контейнером внутри которого может храниться UserControl (я забыл точные имена классов), а затем, когда вам нужно переключить корневой вид, вы делаете RootView.SetView (UserControl view), который будет делать что-то вроде формы.четкая форма.AddChild (вид).
О навигации и использовании контейнера: Ты мог бы создайте сервис для навигации: INavigationService, который вы вводите в конструкторы с помощью метода, подобного INavigationService.NavigateView (String (or Type) viewName, params object [] additionalData)