Question

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.                       
    }
}
  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();
}
Was it helpful?

Solution

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.
}
  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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top