Problem: Prevent a client object from subscribing to the same event multiple times.
Example: You have a view that contains a Navigate event which is raised when the user needs to navigate to the next page.
class View : IView
{
public event NavigationHandler Navigate;
...
public void raiseNavigate()
{
Navigate(typeof(View2));
}
}
When Navigate is raised a presenter should clear the existing view and present a new one.
class FormPresenter
{
... constructor inject a view factory ...
public void NavigateTo(Type type)
{
IView view = viewFactory.Find(type);
view.Navigate+=new NavigationHandler(NavigateTo);
changeView(view);
}
}
This code works well if a new view is returned by the viewFactory every time. However, if the same view is returned from the factory, the presenter will subscribe to the Navigate event multiple times.
Solution: Subscribe to the Navigate event only if the presenter hasn't previously. Declaring the event accessors allows us to manage a single Navigate subscription per client model in the publisher.
Thus, View becomes:
class View : IView
{
private NavigationHandler navigationHandler;
private ArrayList navigateSubscriberInstances = new ArrayList();
public event NavigationHandler Navigate
{
add
{
if (navigationHandler==null || !navigateSubscriberInstances.Contains(navigationHandler.Target))
{
navigationHandler += value;
navigateSubscriberInstances.Add(navigationHandler.Target);
}
}
remove
{
navigationHandler -= value;
navigateSubscriberInstances.Remove(navigationHandler.Target);
}
}
protected void raiseNavigate(Type type)
{
if (navigationHandler!=null)
{
navigationHandler(type);
}
}
}
Why would you ever want to make a field public on the View? Instead of exposing publicly an event, why not just require a method that accepts a delegate, and the view can add the delegate to the appropriate event.
ReplyDeleteThe model view presenter (MVP) implementation wasn't really the focus of the entry; however, I am interested in your suggestion. What do you gain by having a method add the delegate/
ReplyDelete