简体   繁体   中英

MVP view/presenter registration

I'm working on an MVP based GUI architecture for a WinForms application and would like to use Autofac to keep track of the different parts. I keep running into circular component dependencies and would appreciate a gentle push in the right direction.

The architecture is based on this post where the View is as passive as i gets. The View holds no reference to the Presenter. The View is passed to the Presenter on construction. So in the non-DI world you would start your program with:

var MainView = new MainView();
var mainPresenter = new MainPresenter(mainView, new DataRepository());
Application.Run(mainView);

Ok, so the Presenter needs to know about the View instance to do its job. How can I express that in the registration code? This is what I've tried:

builder.RegisterType<MainPresenter>().PropertiesAutowired().SingleInstance();
builder.RegisterType<MainView>().As<IMainView>().PropertiesAutowired().SingleInstance();

And then in Program.cs:

var mainPresenter = Container.Resolve<MainPresenter>();
Application.Run(Container.Resolve<IMainView>() as MainView);

But this way I need to remember to create the Presenter instance. However I would like to express in the registration that if I request a IMainView instance the MainPresenter should be kicked into action. But how....

Any hints, mockery or derisive laughter are welcome

I think you should be able to solve it this way: Register the presenter and view without property injection since you say the view needs no reference to the presenter, and constructor injection is considered best practice in Autofac:

builder.RegisterType<MainPresenter>().SingleInstance();
builder.RegisterType<MainView>().As<IMainView>();

Inject the view into the presenter through constructor and publish it as a readonly property:

public class MainPresenter
{
  // Private variables

  private readonly IMainView _view;

  // Constructor

  public MainPresenter(IMainView view)
  {
    _view = view;
  }

  // Properties

  public IMainView View
  {
    get { return _view; }
  }
}

Then you fire up the application through a single resolve:

var mainPresenter = Container.Resolve<MainPresenter>();
Application.Run(mainPresenter.View as Form);

Finally, if you find later on that you need a reference from the view to the presenter, I think you would have to use property-injection on the view to avoid circular reference exceptions. Then you can register the view like this:

builder.RegisterType<MainView>().As<IMainView>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies);

and supply the view with a read/write property that will be set by Autofac

public MainPresenter Presenter { get; set; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM