5
votes

I'm refactoring a WinForms (.NET 4) application that makes use of a TabControl to contain a UserControl--the UserControl is instantiated in each TabPage with the end result being editors in each tab. These are editing a collection of items that ultimately feed into the object being edited by the form as a whole.

As an example class structure:

  • class School
    • string Name
    • string Address
    • Collection of Courses, each with several appropriate fields (Department, Name, etc.)

(It's not actually a school-related application, but the metaphor works.)

Visually, the set of UserControls manages the Coursees, while the parent Form handles the School information.

Right now, I have a presenter for the Form/School, and a presenter for the UserControl/Course, with a view for each. The School's presenter needs to control some information for the Courses, however. For instance, options selected for one Course restrict options in the others. The School model is handling the calculations of that, but it needs to get to the Course's presenter.

I'm not having much success in finding examples of this type of relationship in MVP discussions, and this is my first time taking an MVP approach. What are good options for handling this? Is it appropriate for the School's presenter to have a collection of the Course's presenters to represent the set? Should the School's view be holding a collection of the Courses' views? (The final UserControls have to end up attached to the form somehow and somewhere, right?)

My main goals are (unsurprisingly) increasing testability and maintainability, and major sources in the process so far have been Michael Feathers' "The Humble Dialog Box" and Jeremy Miller's "Build You Own CAB" series.

1

1 Answers

3
votes

How I deal with similar situation is that parent presenter should know about child presenters (as constructor dependencies that is).

Each child presenter has its view, so in the parent presenter my logic goes something like:

Initialize() - initialize parent - call initialize on each child presenter (this is for fetching all necessary data EXCEPT the data that is primarily shown. For example, if you have a invoice presenter, you need to fetch customer collection from somewhere if you will have customer combobox so that you can change this for an invoice) - embed child views into parent view (parent is usually a form, where children are user controls)

then after that, usually on loading the parent, with some LoadXXX method, I also load children. In your example, it would be something like

schoolPresenter.LoadSchool(school)

which would in turn load the data across all presenters, for example load parent controls with school details, pass the courses collection to the courses presenter etc...

One think that I noticed it is good to do, is to have a Refresh() method on each of these presenters, which basically knows how to load itself based on current status. Maybe you cant have method like this on parent presenter, but simple presenters work fine like this, so that means that in LoadSchool method you can have something like

coursesPresenter.Courses = school.Courses; coursesPresenter.Refresh();