views:

80

answers:

3

Hi,

I have an application that has a window similar to the one bellow .

alt text

The requirement here is that when the user clicks the Save button everything has to get saved. The "Save" and "Reset" buttons are "common" to all tabs. Hence, when the "Personal Information" tab is selected and "Save" is clicked the program should also save changes made in the "Friends" tab and changes made in the "Employment History" tab.

The app already has code for the following and I want to keep this code:

-PersonalInformationView , PersonalInformationPresenter, PersonalInformationModel

-FriendsView, FriendsPresenter, FriendsModel

-EmploymentHistoryView, EmploymentHistoryPresenter, EmploymentHistoryModel

Each presenter has a Save method.

The question is what would be a good design pattern to use taking into consideration that I want to keep the code I already have. Also, I want this window to have model, view, presenter as well. Or maybe I should rephrase my question a bit: what's the best way of including "sub-views", "sub-presenters" when programming MVP ?

Regards, MadSeb

+1  A: 

I personally would suggest making an abstract interface, ISaveable, or osmething and ensure that each of the presenters implement this, than go through each presenter as an object of ISaveable and save each one.

LnDCobra
..but from the presenter of the "main view" I don't have access to the presenters of the "sub views"(PersonalInformationView,FriendsView,EmploymentHistoryView) ..I only have access to the "sub views" themselves...
MadSeb
A: 

My suggestion is to create ISaveableView with save method. Each of your views will implement the interface. I am guessing that your tabs implements the views you've described. When you click the save button you can cast the active tab to ISaveableView and call its save method

sagie
hi, this is a good response but the "Save" method is not part of the view but part of the presenter ......... but I guess I can make a "Save" method in the view and this method would call the "Save" of the presenter.
MadSeb
A: 

I would make your new presenter take in your sub presenters as constructor arguments, something like:

class DialogPresenter {

    private readonly IDialogView view;
    private readonly PersonalInformationPresenter personal;
    private readonly FriendsPresenter friends;
    private readonly EmploymentHistoryPresenter history;

    void DialogPresenter(IDialogView view, PersonalInformationPresenter personal, FriendsPresenter friends, EmploymentHistoryPresenter history) {
        this.view = view;
        this.personal = personal;
        this.friends = friends;
        this.history = history;
    }

    bool Display() {
        this.personal.Display();
        this.friends.Display();
        this.history.Display();

        return this.view.Display() == DialogResult.Ok;
    }

    void Save() {
        this.personal.Save();
        this.friends.Save();
        this.history.Save();
    }
}

Of course, if your presenters had a common interface between them, this could be simplified (and made more extendable) like so:

class DialogPresenter {

    private readonly IDialogView view;
    private readonly IPresenters[] presenters;

    void DialogPresenter(IDialogView view, IPresenters[] presenters)
    {
        this.view = view;
        this.presenters = presenters;
    }

    bool Display() {
        foreach (var item in this.presenters)
            item.Display();

        return this.view.Display() == DialogResult.Ok;
    }

    void Save() {
        var validation = new List<string>();

        foreach (var item in this.presenters)
            validation.AddRange(item.Validate());

        if (validation.Count > 0) {
                _view.ShowErrors(validation);
                return;
        }

        foreach (var item in this.presenters)
            validation.AddRange(item.Save());
    }
}

Edit: Calling code would be something like this:

void DisplayForm() {

    using (var frm = new frmDisplay) {

        //or just use DI to get the models etc
        var personal = new PersonalInformationPresenter(personalModel, frm.PersonalTab);    //some properties to expose your views
        var friends = new FriendsPresenter(friendslModel, frm.FriendsTab);
        var history = new EmploymentHistoryPresenter(employmentHistoryModel, frm.HistoryTab);

        var presenter = new DialogPresenter(frm, personal, friends, history);
        if (presenter.Display()) {    
            presenter.Save();
        }
    }
}

Hope that is of some inpsiration/help :)

Pondidum
This does provide some inspiration indeed. However, I have the following issue with this.The "Save" method of each presenter does data validation before saving and in case it fails *view.DisplayValidationErrors()* is called and a msgbox is shown("Postal Code is missing." etc) If I choose to use the code you suggested the user will get one msg.box for the validation mistakes in the first tab, one msg.box for validation mistakes in the second tab ..but I want all the validation mistakes aggregated in just one msg.box.
MadSeb
I have updated my answer (second block of code) to show how i handle this
Pondidum