How are Views created in MVP? Does the Presenter always create them (in addition to View in case of subviews)? Or is it a separate third-party component or App or something that creates them?
Let's also add that I'm probably going to do this on Dojo Toolkit/ExtJS (JavaScript that is).
So, I have these code lines:
var v = new MyApp.view.User();
var p = new MyApp.presenter.User();
where should both lines go exactly? Does the presenter instantiate the view, or vice-versa? And what instantiates the first instance?
It depends ...
The main goal of MVP is to separate complex decision logic from UI code in such a way that both become easier to understand and to maintain. Often another goal is to make the decision logic in the presenter testable.
The MVP pattern was described by Fowler in 2004 and he retired it in 2006 by splitting the pattern into Supervising Conroller (SC) and Passive View (PV). In SC, the View is bound to the Model but not in PV; in PV, the View is only changed by the Presenter directly.
In both SC and PV, the Presenter has to update the View and react to changes the user made to the View, such as entering text or pressing a button. When you let the View call methods on the Presenter, then the problem you describe arises because the View needs a reference to the Presenter and vice versa. If you do this, you simply can make a decision who starts it all up. Options are:
The View creates an instance of the Presenter. When the View is loaded, it passes itself to the Presenter in an initialize function on the Presenter.
The other way around: Presenter creates View and passes itself to the View in an initialize function on the View.
You introduce a third object that creates both View and Presenter, wires them together and initializes them both.
All options allow you to reach "MVP goals" of separation of concerns and increased testability of decision logic. I don't think any of these methods is theoretically right or wrong –you just have to pick the one that is most appropriate to the technology you use. And it's best to be consistent in your choice throughout the application.
These are your options:
var cvp = new ContactViewPresenter(new ContactView());
ContactViewPresenter constructor sets this.view = viewParam, and sets this.view.presenter = this.
It keeps the code in the Presenter, it can swap out views if necessary, and it could pass in a mock of the view for testing.
var cv = new ContactView(new ContactViewPresenter());
ContactView constructor sets this.presenter = cvpParam, and this.presenter.view = this.
Some logic in View, but not a lot. Can swap out presenter if necessary.
ContactView cv = new ContactView();
ContactViewPresenter cvp = new ContactViewPresenter();
cv.presenter = cvp;
cvp.view = cv;
cv.init();
cvp.init();
This is a lot more code.
ContactViewPresenter cvp = new ContactViewPresenter();
Constructor creates sets this.view = new ContactView() and this.view.presenter = this.
ContactView cv = new ContactView();
Constructor sets this.presenter = new ContactViewPresenter() and this.presenter.view = this
The last two seem a bit too coupled.
One is nice in that the code stays in the Presenter, and seems to allow for easier testing.
Two is nice in that you don't have to care about the Presenters too much and can worry about your Views more.
I don't think the Presenter should instantiate the view, that should be done by an entity (not in the data-oriented sense, I mean a general entity) outside of the MVP triad. For example, an Inversion of Control (IoC) framework (if you haven't heard about IoC, check Martin Fowler's article), or some application module responsible for user configuration.
If you are using WebForms then the WebForm OnLoad or Init should be the place where you create the Presenter - this is then passed an interface reference to the View which the WebForm implements.
So, something like this:
Presenter _presenter;
OnLoad(object sender, EventArgs e)
{
_presenter = new Presenter(this);
_presenter.Initialise();
}
And the Presenter constructor is defined thus:
public class Presenter
{
public Presenter(IView viewReference)
{
_viewReference = viewReference;
}
}
I may have the terminology slightly wrong but I think you need to identify the composition root of your interaction; what is the thing that begins the interaction?
In the Webforms example I gave, the Webform is created by the Http pipeline, the OnInit or OnLoad event is the first point in the pipeline ( depending on what context you need ) that you can 'hook in' to the process. Thus, you create a Presenter and give it your concrete instance of a Webform as a View Interface.
I don't know the Javascript frameworks you are discussing but I presume there is an initialisation / invocation step - in ASP.NET MVC this is when an ActionInvoker gets involved, it's the Main in a Console App.
Related
I think I'm on my way to finally grokking MVVM. I was just looking at a situation I found myself in and I'm wondering if I should combine two of my layers. I currently have a structure like this:
Domain models (in a separate .net project)
WPF-side "models" which wrap domain models and track dirty state
WPF ViewModels
Views
The question is whether I should combine 2 and 3. Right now #2 is the layer that gets passed around by my mediator to facilitate all the viewmodels knowing what document is currently opened. But I think my code for 2 and 3 is too similar and is unnecessary duplication at this point.
Example:
// in layer 2, class ProjectDocument
// Project is an instance of the domain model
public string Name
{
get { return Project.Name; }
set
{
if (Project.Name == value) return;
Project.Name = value;
Dirty = true;
}
}
// in layer 3, class ProjectSettingsViewModel
// _project is a ProjectDocument
public string Name
{
get { return _project.Name; }
set
{
_project.Name = value;
OnPropertyChanged("Name");
}
}
Seeing that struck me as unnecessary. So should I combine them? On one hand, it would remove a lot of redundant code and I'd have fewer places to update when I change things. On the other, I might be giving one class too much responsibility, and also it seems inappropriate for an actual ViewModel to be passed around to other VMs via my mediator. The ProjectSettingsViewModel wouldn't use even half of the fields on ProjectDocument if they were combined.
Maybe I'm looking at this the wrong way. Is there a better way to reduce the duplication while still keeping the responsibilities separate?
I have a master viewmodel that handles application states like which document/tab/window is open and I have an ISettingssService for other global needs. Passing one viewmodel to another is discouraged and you might want to think about creating am iSettings service that can be injected into the viewmodels, then the viewmodels can interact with "global" settings but the viewmodels are still decoupled because they do not depend on another viewmodel.
So, I would not combine them. Either I would have a dictionary of documents that can be open in the master viewmodel with a current open doc property or move this logic to a service/interface that gets used by each viewmodel.
Hope this helps.
Please consider following Backbone application structure:
AppView
Subview
FirstSubviewInQuestion
Subview
Subview
SecondSubviewInQuestion
Application view creates and stores a collection of special items. At a certain time the first and the second subview needs to get access to that collection. Now what is the best way to pass the collection it to them?
I myself see some ways, yet each has a downside:
1) Create instance of that collection not inside the App View but even more globally and then pass it around as dependency (project uses RequireJS; so it would be passed to AppView and both Subviews).
Downsides: app view is supposed to be the top most element in application. Yet suddenly we have some instances of collections floating above.
2) Or I can do following:
// some subview
var collection = {};
Backbone.trigger( "item:getSpecialItems", collection);
// now the collection has data
// app view
this.listenTo( "item:getSpecialItems", function(obj) {
// copy collection to passed object
_.extend(obj, this.specialCollection);
});
Downsides: we are triggering a global event. We know that only the app view would respond, but it feels like a bad design. Plus, this way to pass the collection seems like a hack.
Maybe there are some other clever ways to do it?
I would say #1.
app view is supposed to be the top most element in application
Right, but you're talking about (I think) a Collection, not a View; the two are totally separate parts of your application (in MVC the first is the "M" and the second is the "V"). By definition, if your views are driven by your data, the data must be "higher" (in the dependency tree) than any view, so I don't see anything wrong with that approach.
If your goal is to get a shared instance of the collection, my approach would be to pass that down from the parent to "subview" and from subview into its children. However, I wouldn't necessarily use require to pass around a singleton of this collection.
You could also pull out all of the logic from the view regarding the special methods for "creation and storage of special objects" into a helper class whose sole domain is just this. That helper then becomes a utility available from outside the view hierarchy, perhaps even globally or via require.
In my example I have a parent model (ModelParent) with two collections (A and B), which hold ModelA's and ModelB's respectively. There are associated views for each model (ViewParent, ViewA, and ViewB)
I would like a function in ViewA to add a new item to CollectionB.
What's the best way to do this? (couple of possibilities below):
Should ViewA be passed a reference to ViewParent, when it is created? How best to do this? (as far as I know there is now in build parent reference)
Should ViewParent be stored in the window scope, so that ViewA can refrence it like window.ViewA? (This seems wrong to me)
Another alternative than listening directly to events from your collection, is the use of an eventBus. Derick Bailey from Los techies wrote a nice article where he introduces the idea of communication between different components (in his case views) via an eventBus.
If you are firm with coffeescript - and possibly even if you're not - you should also check this nice extension from Adam Thurlow.
Side note: If your situation simply requires communication between the two elements an eventBus is most likely overkill, although the idea is imho ultra simple. Apart from that, I am of the believe, that a central component for communication is worth the effort as it simplifies messaging, supports decoupling and gives your architecture a reliable consistency.
I would consider thinking about it a different way. I believe it would be cleaner if you didn't have to pass references all around your views. Instead, use backbone's built in event model and keep the "add new item to CollectionB" logic inside ViewParent. When ViewParent instantiates ViewA, you could immediately bind to an event on it:
this.viewA = new ViewA({});
this.viewA.bind("some_event_that_requires_adding_to_collection", this.onViewAEvent);
Inside ViewA, whenever you want to add to CollectionB, just trigger the event:
this.trigger("some_event_that_requires_adding_to_collection", itemIWantToAdd);
Add additional arguments to the trigger call to pass them to any callback bound to the event.
I'm trying out Ninject with a winforms app (basically a sketch, I'm using it sort of like a kata, but nothing so rigorous or specific) in .net 4.
To create the main form, I'm doing something like:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
[...]
IKernel kernel = BuildKernel();
Application.Run(kernel.Get<frmMain>());
}
static IKernel BuildKernel()
{
var modules = new INinjectModule[]
{
[..modules]
};
return new StandardKernel(modules);
}
}
Fine. This creates a main form and displays it nicely, passing the appropriate interface implementations to the injected constructor.
Now what? My application is an MDI and will have several child windows for manipulating the application model. I don't have a reference to the kernel anymore, so how am I supposed to Get() these forms? The obvious answer is 'pass the kernel to the form' I suppose, but that's a horribly messy strategy and I'm sure that doesn't fit into the philosophy of DI.
I will point out here that the documentation for Ninject 2 sucks. Everything I can find repeats the basic examples, without really explaining how DI using Ninject makes anything easier. The standard of example given isn't complicated enough to make the trouble of coding and creating modules and bindings worthwhile.
edit #1:
Having studied the links kindly provided by Sam Holder, I'm trying out the 'composition root' approach. My architecture now forces all the Forms it uses to derive from a CompositedForm with constructor semantics thus:
[Inject]
public CompositingForm(ICompositionRoot CompositionRoot)
{
InitializeComponent();
this.CompositionRoot = CompositionRoot;
}
public readonly ICompositionRoot CompositionRoot;
public CompositingForm() : this(new DummyCompositionRoot()) { }
The second constructor is for the benefit of the Forms Designer, which is stupid and can't understand the form markup unless you provide an empty constructor. Now, every form created using IKernel.Get<AForm>() will (should) have a composition root injected into it.
So, as I am a slow learner - now the question is really 'What should go in this composition root'?
can't you pass a factory for creating the child forms to the forms constructor, and the form uses this to get them, then ninject will wire up the factory dependency when the form is created using the get?
I think you should configure everything in the application root using the DI container and after that the container shouldn't be needed, but I've not really used DI containers in anger, and not NInject at all, so am going on what I've read...
This answer may help
Note: I do not know much about Ninject but i worked with Spring.net that is much more complicated. The principles behind sould be something similar.
Sam Holder answer is excellent if you have several objects of one (injected) type to create (for example CustomerOrderItem).
If you just want to wire your mainform i would sugest that your mdi-frmMain constructor gets parameters for every childwindow it should contain and let Ninject create and insert the childwindows. This way there is no need to Reference NInject outside "class Program
". This is called Constructor-Injection.
Alternatively you can add a method to the form that adds a page to you mdi (MethodInjection).
static void Main()
{
[...]
IKernel kernel = BuildKernel();
var main = kernel.Get<frmMain>();
main.AddClientForm(kernel.Get<CustomerForm>()) ;
main.AddClientForm(kernel.Get<InvoiceForm>()) ;
Application.Run(main);
}
Thanks to João Almeida and Kellabyte I have found a method that is more or less satisfactory:
Define a custom Attribute which exposes whatever business rules you care about;
Define an implementation of IInjectionHeuristic which recognises this attribute;
Use a ViewModelLocator to load modules into the ninject kernel.
I am getting my knickers in a twist recently about View Models (VM).
Just like this guy I have come to the conclusion that the collections I need to expose on my VM typically contain a different type to the collections exposed on my business objects.
Hence there must be a bi-directional mapping or transformation between these two types. (Just to complicate things, on my project this data is "Live" such that as soon as you change a property it gets transmitted to other computers)
I can just about cope with that concept, using a framework like Truss, although I suspect there will be a nasty surprise somewhere within.
Not only must objects be transformed but a synchronization between these two collections is required. (Just to complicate things I can think of cases where the VM collection might be a subset or union of business object collections, not simply a 1:1 synchronization).
I can see how to do a one-way "live" sync, using a replicating ObservableCollection or something like CLINQ.
The problem then becomes: What is the best way to create/delete items?
Bi-directinal sync does not seem to be on the cards - I have found no such examples, and the only class that supports anything remotely like that is the ListCollectionView. Would bi-directional sync even be a sensible way to add back into the business object collection?
All the samples I have seen never seem to tackle anything this "complex".
So my question is: How do you solve this? Is there some technique to update the model collections from the VM? What is the best general approach to this?
Personally, I use an ObservableCollection in my model and my viewmodel.
class Model
{
public ObservableCollection<Foo> Foos;
}
class ViewModel
{
public Model Model;
public ObservableCollection<FooView> Foos;
public ViewModel()
{
Model.Foos.CollectionChanged += OnModelFoosCollection_CollectionChanged;
}
void OnModelFoosCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Foo re;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
re = e.NewItems[0] as Foo;
if (re != null)
AddFoo(re); //For other logic that may need to be applied
break;
case NotifyCollectionChangedAction.Remove:
re = e.OldItems[0] as Foo;
if (re != null)
RemoveFoo(re);
break;
case NotifyCollectionChangedAction.Reset:
Foos.Clear();
/* I have an AddRange in an ObservableCollection-derived class
You could do Model.Foo.ForEach(ree => AddFoo(ree));
*/
var converter =
from ree in Model.Foo
select new FooView(ree);
Reports.AddRange(converter);
break;
default:
//exercise for the reader :)
s_ILog.Error("OnModelFoosCollection_CollectionChangedDid not deal with " + e.Action.ToString());
break;
}
}
void AddFoo(Foo f)
{
Foos.Add(new FooView(f));
}
void RemoveFoo(Foo f)
{
var match = from f in Foos
where f.Model == f //if you have a unique id, that might be a faster comparison
select f;
if(match.Any())
Foos.Remove(match.First());
}
}
Now, when you remove something from the Model's Foo collection, it will automatically remove the corresponding FooView. This corresponds with how I think about this sort of thing. If I want to delete something, the Model is where is really needs to be deleted.
It feels like a lot of code, but it isn't that much, really. I'm sure one could build a generic version of this, but IMO you always end up wanting custom logic dealing with addition/removal of elements.
I too am struggling with the bi-directional sync of two collections for use with WPF via MVVM. I blogged MVVM: To Wrap or Not to Wrap? How much should the ViewModel wrap the Model? (Part 1) and MVVM: To Wrap or Not to Wrap? Should ViewModels wrap collections too? (Part 2) regarding the question, including some sample code that shows a two way sync. However, as noted in the posts, the implementation is not ideal. I would qualify it as a proof of concept.
I like the BLINQ, CLINQ, and Obtics frameworks that Alex_P posted about. These are a very nice way to get one side of the sync behvaior. Maybe the other side (from VM to Model) can be implemented via an alternate path? I just posted part 3 on my blog that discusses some of this.
From what I can see, bi-directional via BLINQ and CLINQ is not supported in cases where the LINQ statement projects the data to a new structure.
However, it does look like CLINQ may support Bi-Directional syncing in cases where the LINQ query returns the same datatype as the underlying collection. This is more of a filtering scenario, which doesn't match the use case of a ViewModel wrapping the data in the Model.
The only situation, when you might need the two-way synchronization, is when the control that you use to visualize your collection of VMs does not let you know of user's intention to create or remove an item. I.e. the control deals directly with your collection of VMs and the ONLY way you know the item has been added/removed, is by monitoring the collection of VMs. If this is not the case then you can implement one way sync and add/remove items directly on model's collection.
EDIT: Take for example WPF DataGrid
control bound to observable collection
of ItemViewModels. If its
CanUserAddRows property is set to true
and the user starts typing in the
empty row at the bottom, the DataGrid
will use default constructor of your
ItemViewModel to create a loose item
and then will add it to the
collection. There is no indication
from DG that it wants to add an item
the collection.c
I can't think of any
other control that is complicated
enough to be able to add items to
collection on its own.
The opposite
scenario is when you have ListView
bound to your collection and a command
which indicates user's intention to
add new item - then in command handler
you simply add new item to DataModel
and let the one-way sync do the rest of
the job. In this case ListView is not
able to add to the collection it
presents.
As to the sync process itself, look at Bindable LINQ project - it can minimize the amount code and improve readability. For example the code Tom posted will translate into something like this:
class ViewModel
{
public Model Model;
public ObservableCollection<FooView> Foos;
public ViewModel()
{
Foos = from foo in Model.Foos.AsBindable()
select new FooView(foo);
}
}
EDIT 2: After using B-LINQ for some time now I should say that you might have performance issues with it. I have used it to synchronize relatively big collections (hundreds of elements) collections with tens of elements being added and removed every second and I had to give it up and implement synchronization the way Tom had suggested.
I still use B-LINQ though in those parts of the project where collections are small and performance is not an issue.
I've written some helper classes for wrapping observable collections of business objects in their View Model counterparts here, maybe it should be extended to go the other way. always looking for contributions...
I have proposed a general Undo / Redo framework based in MVVM, that uses some techniques related to the problem you describe. It uses collections implementing this interface:
public interface MirrorCollectionConversor<V, D>
{
V GetViewItem(D modelItem, int index);
D GetModelItem(V viewItem, int index);
}
(V is for the ViewModel items, D for the model items)
Using this interface it automatically synchronizes the viewmodel collection when the model collection changes. If you change the viewmodel the change is simply redirected to the model collection.
The GetViewItem function gives you some flexibility in how the viewmodel objects are related to his model counterparts.
You can find the details here.
(I admit that the construction is quite complex and I will be very happy to listen to suggestions).
With my ObservableComputations library you can create ObservableCollection that is result of computing over another ObservableCollection and is synchoronized with it. You make standart operations (add, remove) on the source colection: computed Collection reflects all the changes:
Filtering<Order> expensiveOrders = orders.Filtering(o => o.Price > 25);
expensiveOrders.CollectionChanged += (sender, eventArgs) =>
{
// see the changes (add, remove, replace, move, reset) here
};
// Start the changing...
orders.Add(new Order(8, 30));
orders.RemoveAt(1);
orders[0].Price = 60;
orders[4].Price = 10;
orders.Move(5, 1);
orders[1] = new Order(10, 17);