How to expose properties of a user control in .NET for the MVP pattern
I am implementing a simple UserControl
that is actually a fancy TextBox
. One of its features is that you can set a formatting specification and this formatting get's applied to its contents automatically. For exa开发者_如何转开发mple, if you set the formatting specification to "000"
and the contents are "42"
, then "042"
will appear.
I am implementing this UserControl
following the MVP pattern. The implementation is similar to this: how Implement usercontrol in winforms mvp pattern?. Also, check this question: passive view and display logic
Approach #1
My Title
property in the View
looks like this:
private string title;
public string Title {
get { return title; }
set { title = value; titleTextBox.Text = presenter.Format(title); }
}
It is my feeling that this implementation adds unnecessary coupling. For example, if I change the Presenter
's Format
method then I will have to go through all View
s and change appropriately the call statement.
Approach #2
My Title
property in the View
looks like this:
public string Title {
get { return presenter.Title; }
set { presenter.Title = value; }
}
My Title
property in the Presenter
looks like this:
private string title;
public string Title {
get { return title; }
set { _view.SetTitle(this.Format(value); }
}
Now I have to add the SetTitle
method in the View
interface and in the View
implementation:
public void SetTitle(string title) {
titleTextBox.Text = title;
}
So, with this approach I get this ugly SetTitle
Java-like method.
Approach #3
Instead of calling SetTitle
create a new property RealTitle
in the View
and set that. It remains ugly with this Real
prefix.
Your approach
Can you think of a better way?
Use case
The UserControl
should be used like this:
var c = new FancyTextBox();
c.Format = "000";
c.Text = "42";
Controls.Add(c);
This snippet should display "042"
inside the UserControl
.
The big picture
Form FancyTextBoxView FancyTextBoxPresenter
| | |
| ftb.Text = "42" | |
|-------------------->| |
| | |
| | A |
| |----------------------------->|
| | |
| | B |
| |<-----------------------------|
What are the A and B actions? I want the formatted text to appear in the UI. The formatting code is in the Presenter
. The View
has a titleTextBox
that will hold the text in the UI.
Why don't you just define your View's Title property like this?
public string Title {
get { return titleTextBox.Text; }
set { titleTextBox.Text = value; }
}
There is absolutely no reason to define an additional SetTitle method. Also, in MVP, your view should never know about your Presenter.
Then whenever your Format function gets triggered, you can set the title of your view from there, for example:
void OnFormatCalled()
{
_view.Title = FormatTitle(_view.Title);
}
I normally inject the View interface (and Model interface) into the Presenter. Now you have one place to worry about dependencies and testing.
Have your view fire an event when the title is set and have your Presenter subscribe to it. Then the Presenter can format the text and set the title on the view - the Presenter is in charge of the presentation of the view, the view just renders stuff. In this way the view is really dumb with little logic at all. This lends itself to being mocked out during unit testing and makes the presenter really easy to test.
Also notice how the formatting logic is also injected into the Presenter through a delegate property, thus decoupling the formatting from the presenter and making it changeable and testable. Just one way of doing it anyway...I like this approach.
public class Presenter
{
private IView _view;
private IModel _model;
public Func<string, string> TitleFormatter { get; set; }
public Presenter(IView view, IModel model)
{
_model = model;
_view = view;
_view.OnSetTitle += (s, e) => {
_view.Title = TitleFormatter(e.Text);
};
}
}
public View : IView
{
public event EventHandler<TitleChangedEventArgs> TitleChanged;
public SomeUserActionEvent(object sender, SomeUserInterfaceEventArgs e)
{
TitleChanged(e.Text);
}
}
精彩评论