I don't think it is a wise idea to have View and Presenter being coupled so tight.
Based on either the Passive Screen
or Supervising Presenter the presenter and the view are separated by an interface that is implemented by the view. The presenter calls the interface. Here is an example of a supervising presenter.
PRESENTER
this class has no dependency on the used GUI library
public class Presenter
{
IView view;
public Presenter(IView view)
{
this.view = view;
}
public void ValidateInPut(string value)
{
if (!String.IsEmptyOrNull(value) && value.Contains("9"))
{
view.ShowError("The value in the Text box is invalid");
}
}
}
ViewInterface
public inteface IView
{
void ShowError(string message);
}
VIEW
public class Form1:Form, IView
{
private Presenter presenter;
public Form1()
{
this.presenter = new Presenter(this); // or have a Dependcy Injection Framework do this
}
private void txtACNo_Validating(object sender, CancelEventArgs e)
{
presenter.ValidateInPut(txtACNo); // validate
}
public void IView.ShowError(string message);
{
MessageBox.Show(mesage);
}
}
Rationale
By utilizing your view and presenter the presenter (with all its (busines)logic) becomes easily testable or the view can be replaced by a WebPage without the need to adapt your presenter logic.
Test
public class Test:IView
{
bool showErrorCalled = false;
public void Test()
{
var p = new Presenter(this);
showErrorCalled = false;
p.ValidateInput("8");
Test.Assert(showErrrocalled);
}
public void IView.ShowError(string message);
{
showErrorCalled = true;
}
}
WebPage
public Default:Page, IView
{
private Presenter presenter;
public Default()
{
this.presenter = new Presenter(this);
}
public Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
presenter.ValidateInput(txtAcNo.Text);
}
}
public void IView.ShowError(string message);
{
Error.Text = message;
}
}
PS
Remember that the cast operator on an object may fail. Your code
var controller = (TextBox)sender;
will only work as long as sender
is a TextBox
. It is better to check if there is a more generalized type up the hierarchy that still provides you with the needed interface. In your case that could be Control
that has a Text
property as well. A more defensive approach would be:
var controller = sender as Control; // try to cast, if not return null
if (controller != null)
{
// do stuff with controller
}
else
{
// logging
Debug.WriteLine("controller is null");
}
There are several variants of the MVP around since its original design in 1996 by Mike Potel. Martin Fowler discusses some of them in another article on GUI architecture.
One of the key differences between the variants is whether the view is totally isolated from the model or not:
- In the first case, the presenter is the man in the middle of a "passive view" and the model.
- In the second case, the presenter is a "supervising controller", but there are interactions directly between the view and the model. Potel's paper describe well the kind of interactions: the view can request data from the model, and the model can notify the view of some events.
In none of the case would the view directly change the model. The change of the model goes always via the Presenter (or the controller in an MVC).
Remark 1: The MSDN article shows only one arrow directly from the view to the model, in its introduction on the MVC (Model View Controller) part. The arrow is in the wrong direction, but the text is correct: the view can access to the model, and change itself (i.e. not the model, but redraw itself) upon change of the model's data.
Remark 2: The MSDN article also shows Microsoft's MVVM pattern, which is roughly a MVP, but the presenter is ambiguously called "ViewModel". But again, the View therein doesn't updated the model directly.
Your edit:
The code of your edit shows a bidirectional data binding, where update of data in the view would trigger directly a change in the model. This indeed contradicts the original MVP pattern where the View informs the Presenter of desired changes via an "Interactor" and the Presenter has the monopoly to invoke "Commands" to update the Model.
Remark 3: I think the author of this MSDN blog was more interested in introducing the MVVM architecture than writing a comprehensive in-depth article, like Martin Fowler did, on the other architectures. I think also that Microsoft's ADO databinding architecture dating back to the early days of the .net framework favored such a mixed design and made a classic MVP less trivial to implement (it required a DataObjectSource to isolate data model access).
Best Answer
In order to keep your code organized and maintainable, I would say it is better to handle the event in the Presenter. The purpose of the view is to display information to the user. The purpose of the presenter is to execute logic and work as a middle man between data and users.