How to Form.ShowDialog() using MVP and Passive Views?

Summary

I'm experimenting with the MVP pattern in a Windows Forms application.

I'd like to make both my Presenters and Views platform agnostic, so if I wish to port my application to another platform, say the Web or mobile, I simply need to implement the views with platform dependant GUI, and my presenters can still be platform independent.

And now I wonder, how to ShowDialog() using MVP and Passive Views?

To my understanding so far, passive views shouldn't know/care about any presenter. They don't even know it exists. So, the solution presented in this question's answer is not suitable, according to me: Refactoring Form.ShowDialog() code to MVP

Some code samples to help on the understanding:

ApplicationView

public partial class ApplicationForm : Form, IApplicationView {
    // I ensure that all the IApplicationView events are raised 
    // upon button clicks text changed, etc.
    // The presenter, which this view ignores the existence, 
    // is subscribed to the events this view raises.
}

ApplicationPresenter

public class ApplicationPresenter 
    : Presenter<IApplicationView>
    , IApplicationPresenter {
    public ApplicationPresenter(IApplicationView view) : base(view) {
        View.OnViewShown += OnViewShown;
    }

    public void OnViewShown() {
        IAuthenticaitonView authView = new AuthenticationForm();
        IAuthenticationPresenter authPresenter = new AuthenticationPresenter(authView);
        authPresenter.ShowDialog(); // 1.                       
    }
}
  • This is where I'm struggling. The ApplicationPresenter is like the master in the universer and may be aware of the user authentication through both the IAuthenticationView and IAuthenticationPresenter .
  • IAuthenticationView

    public interface IAuthenticationView : IDialogView {
        string ErrorMessage { get; set; }
        string Instance { get; set; }
        IEnumerable<string> Instances { get; set; }
        string Login { get; set; }
        string Password {get; set; }
    
        void EnableConnectButton(bool enabled);
    
       event VoidEventHandler OnConnect;
       event SelectionChangedEventHandler OnDatabaseInstanceChanged;
       event VoidEventHandler OnLoginChanged;
       event VoidEventHandler OnPasswordChanged;
    }
    

    IDialogView

    public interface IDialogView : IView {
        void ShowDialog();
    }
    

    IView

    public interface IView { 
        void Show();
    
        event VoidEventHandler OnViewInitialize;
        event VoidEventHandler OnViewLoad;
        event VoidEventHandler OnViewShown;
    }
    

    IAuthenticationPresenter

    public interface IAuthenticationPresenter : IPresenter<IAuthenticationView> {
        void OnConnect();
        void OnViewDatabaseInstanceChanged(SelectionChangedEventArgs e);
        void OnViewLoginChanged();
        void OnViewPasswordChanged();
    }
    

    IPresenter<V>

    public interface IPresenter<V> where V : IView {
        V View { get; }
    
        OnViewInitialize();
        OnViewLoad();
        ShowView();
    }
    

    Based on these premisses:

  • The presenter shall be platform agnostic
  • Only the view knows how to show/display itself (WPF, Mobile, Silverlight, Web, WinForms...)
  • The view MUST provide a way to show itself
  • The view doesn't have to be platform agnostic , since the display will differ from a platform to another
  • But the presenter shall order the view when to show itself
  • I came to this:

    IView

    public interface IView {
        void OnShowView();
    }
    

    IPresenter<V>

    public interface IPresenter<V>where V : IView {
        void ShowView();
        event VoidEventHandler OnShowView;
    }
    

    Presenter<V>

    public abstract class Presenter<V> : IPresenter<V> {
        public Presenter(V view) { 
            View = view;
            OnShowView += View.OnShowView;
        }
    
        public void ShowView() { raiseShowViewEvent(); }
    
        public event VoidEventHandler OnShowView;
    
        private void raiseShowViewEvent() { if (OnShowView != null) OnShowView(); }
    }
    

    So, following the logic of where I struggled so far, I solved it by doing this:

    ApplicationForm

    public partial class ApplicationForm : Form, IApplicationView {
        private void ApplicationForm_Shown(object sender, EventArgs e) { raiseOnViewShown();  }            
    
        private void raiseOnViewShownEvent() { if (OnViewShown != null) OnViewShown(); }
    }
    

    ApplicationPresenter

    public void OnViewShown() {
        // This method is the subscriber of the IView.OnViewShown event
        // The event is raised with the ApplicationForm_Shown event.
        IAuthenticationView authView = new AuthenticationForm();
        IAuthenticationPresenter authPresenter = new AuthenticationPresenter(authView);
        authPresenter.ShowView(); // 1.
    }
    
  • This raises the OnShowView event which the IAuthenticationView has subscribed. Then, back in the form, the view's response to the event is:
  • AuthenticationForm

    public partial class AuthenticationForm : Form, IAuthenticationView {
        public void OnShowView() { ShowDialog(); }
    }
    

    Then, the view shows itself as a dialog/modal window.

    链接地址: http://www.djcxy.com/p/30228.html

    上一篇: 如何在MVP被动视图中显示复杂数据

    下一篇: 如何Form.howDialog()使用MVP和被动视图?