Andrew Kilburn
Andrew Kilburn

Reputation: 72

How to use dependency injection with MVP for WinForms?

So on my view I inject my presenter as I need to do this to be able to use my events. My view looks like this:

     public partial class ImpositionForm : Form, IImpositionFormView {
        private ImpositionFormPresenter presenter;
        private readonly ISignatureSizeManager signatureSizeManager;
        private readonly ISystemVariablesManager systemVariablesManager;
        private readonly string expectedPathToAppSettings = $"{AppDomain.CurrentDomain.BaseDirectory}/PrintAppSettings.txt";

        public event EventHandler<EventArgs> SetSheetSizeAcross;
        public event EventHandler<EventArgs> SetSheetSizeAround;
        public event EventHandler<ErrorEventArgs> Error;
        public event EventHandler<EventArgs> ClearPage;
        public event EventHandler<EventArgs> SetSignatureSize;
        public event EventHandler<EventArgs> ShowSystemVariablesForm;

        public ImpositionForm(ImpositionFormPresenter _presenter, ISignatureSizeManager _signatureSizeManager, 
            ISystemVariablesManager _systemVariablesManager) {
            presenter = _presenter;
            systemVariablesManager = _systemVariablesManager;
            signatureSizeManager = _signatureSizeManager;
            InitializeComponent();
        }

            //Other code
}

And I inject the view when using my constructing my presenter:

  public class ImpositionFormPresenter {
        private readonly ISignatureSizeManager signatureSizeManager;
        private readonly ISystemVariablesManager systemVariablesManager;
        private readonly SystemVariablesFormPresenter systemVariablesFormPresenter;
        private readonly string pathToAppSettings = $"{AppDomain.CurrentDomain.BaseDirectory}/PrintAppSettings.txt";
        private readonly IImpositionFormView view;

        public ImpositionFormPresenter(IImpositionFormView _view, ISignatureSizeManager _signatureSizeManager,
            ISystemVariablesManager _systemVariablesManager, SystemVariablesFormPresenter _systemVariablesFormPresenter) {
            view = _view;
            signatureSizeManager = _signatureSizeManager;
            systemVariablesManager = _systemVariablesManager;
            systemVariablesFormPresenter = _systemVariablesFormPresenter;
            InitialiseEvents();
        }
        private void InitialiseEvents() {
            view.SetSheetSizeAcross += SetSheetSizeAcross;
            view.SetSheetSizeAround += SetSheetSizeAround;
            view.Error += LogErrorToView;
            view.SetSignatureSize += SetSignatureSizeValues;
            view.ShowSystemVariablesForm += OpenSystemVariablesForm;
        }

        //Other code
}

This is an issue because I receive a loop where the view relies on the presenter and the presenter relies on the view.

However, I'm not sure how to solve this issue creating new instances of my presenter and view instead of injecting them. Can anyone help me so I can continue using dependency injection?

Upvotes: 1

Views: 776

Answers (1)

John Cleaver
John Cleaver

Reputation: 121

The view / form should not have a reference to the presenter at all. Any communication to the presenter should be done via events that the presenter subscribes to.

From there you can either have the Form instantiate the concrete presenter and pass a reference to itself or you can have your composition root / IOC container create both and pass the view to the presenter. In the former case, the concrete view will need to somehow get all of the other dependencies that the presenter requires.

See this answer for more on the composition root.

The thing to watch out for here is that the subscription creates a circular reference, which prevents garbage collection. For this reason, you should have the view trigger an event indicating that it is closing. The presenter can then be garbage collected normally.

Upvotes: 1

Related Questions