views:

388

answers:

2

I'm building an application using the Supervising Controller pattern (Model View Presenter) and I am facing a difficulty. In my page I have a repeater control that will display each item of a collection I am passing to it. The reapeater item contains 2 dropdown list that allow the user to select a particular value. When I click the next button, I want the controller to retrieve those values.

How can I do that I a clean way?

+1  A: 

When controller-view interation get's too complex I usually split them up into subcontrollers and subviews.

You can have the items in the repeater be user-controls that have their own views and controllers. Your main view can then have a list of subviews(usercontrols) that have their own controllers that are maintained by the main controller.

When the user clicks next your main controller can signal all the subcontrollers to refresh their items from their views.

Mendelt
+1  A: 

You can also make a 'widget' interface for the drop down. I'll give you an easy example of a some working code for a TextBox widget so you get the idea.

public interface ITextWidget
{
    event EventHandler TextChanged;
    string Text { get; set; }
}

public abstract class TextWidget<T> : ITextWidget
{

    protected T _wrappedWidget { get; set; }
    public event EventHandler TextChanged;

    protected void InvokeTextChanged(object sender, EventArgs e)
    {
        var textChanged = TextChanged;
        if (textChanged != null) textChanged(this, e);
    }

    public abstract string Text { get; set; }
}

Notice that so far everything is technology agnostic. Now here's an implementation for a Win Forms TextBox:

public class TextBoxWidget : TextWidget<TextBox>
{

    public TextBoxWidget(TextBox textBox)
    {
        textBox.TextChanged += InvokeTextChanged;
        _wrappedWidget = textBox;
    }

    public override string Text
    {
        get { return _wrappedWidget.Text; }
        set { _wrappedWidget.Text = value; }
    }
}

This gets instantiated in the Form itself, which back to MVP is also the IViewWhatever:

public partial class ProjectPickerForm : Form, IProjectPickerView {

    private IProjectPickerPresenter _presenter;
    public void InitializePresenter(IProjectPickerPresenter presenter) {
        _presenter = presenter;
        _presenter.InitializeWidgets(
            ...
            new TextBoxWidget(txtDescription));
    }
            ...
}

And in the Presenter:

public class ProjectPickerPresenter : IProjectPickerPresenter
{
    ...
    public void InitializeWidgets(ITextWidget descriptionFilter) {

        Check.RequireNotNull<ITextWidget>(descriptionFilter, "descriptionFilter");
        DescriptionFilter = descriptionFilter;
        DescriptionFilter.Text = string.Empty;
        DescriptionFilter.TextChanged += OnDescriptionTextChanged;

    }
    ...

    public void OnDescriptionTextChanged(object sender, EventArgs e) {
        FilterService.DescriptionFilterValue = DescriptionFilter.Text;
    }

It's looks worse than it is to setup because most of the work is fairly mechanical once you get the idea. The clean part is that the presenter can get (and set) whatever info it needs on the widget without knowing or caring what the actual implemented widget is. It also lends itself to reuse with other widgets (you wind up building a library of them) of the same type (Win Forms here) and in other UI technologies as needed (once you have the interface / base class the implementation in another technology is trivial). It also is easy to test with mock objects because you have the interface. And your UI is now wonderfully ignorant of just about everything but UI related tasks. The downside is the bunch of classes per widget and a little learning curve to get comfortable with it.

For your drop down, your might just need the SelectedIndexChanged type event, which you'd substitute for this examples TextChanged event.

Cheers,
Berryl

Berryl