Search code examples
design-patternsmodelviewtabsmvp

GUI Design Pattern , MVP, Tab Control


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

alt text http://a.imageshack.us/img137/7481/screenshotxh.jpg

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


Solution

  • 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 :)