Implementing MVP

Sep 21, 2010 at 10:55 AM

I'd like to implement MVP using CM, well to be more precise I want to implement something like the MVP-VM architecture described by Davy Brion. In a nutshell, the Actions are stripped out of the view-model and put into the presenter.

Is there any guidance on using MVP with CM anywhere? What I specifically want advice on is

  • How to instantiate the presenter along with the view and view-model.
  • How to bind actions in the view to methods in the presenter
  • How to achieve a presenter first architecture (e.g. the presenter is responsible for populating the view-model and presenting it to the view)

Many thanks in advance for any help.

Richard Nagle

Sep 21, 2010 at 2:06 PM
Edited Sep 21, 2010 at 2:14 PM

It's a pretty vast subject, and also involves quite a lot personal preference and decision.
I'll put down some considerations as a start point for further investigation and attempts, hoping that this could help you finding your way into the framework.
As far I understood reading the post, the main point is separating the "active" part of the VM into a Presenter and leaving in the VM just what is needed to facilitate the binding against a WPF/SL UI.

This could be achieved by simply leveraging composition at VM level.
You can use CM "application model" related classes (Conductor and Screen) to implement what you would call "Presenter" (which, funny enough, is the name they had in Caliburn v1.1); then you might create some POCO object (implementing INPC) to realize your VMs and expose them as properties in your presenter.

In this scenario, the view can simply invoke actions living in the Presenter with CM conventional binding or with explicit Message.Attach; the data held by the VM exposed by each Presenter can be bound to UI with conventional binding (using "_" to compose the property path in a valid element name; ex.: Name="ViewModel_MyProperty") or with explicit binding (ex.: {Binding ViewModel.MyProperty} ).

You might also need to access the view through an interface from the Presenter (Passive View variant): you can do this implementing IViewAware in the Presenter, so you can accept the view instance created by the framework, cast it to the known interface and store its reference.

My poor English and the terrible overload and overlapping of terms don't help me to explain, so please feel free to ask further clarifications if needed.

 

Coordinator
Sep 21, 2010 at 2:14 PM

To piggyback on what Marco has already said, you should have a look at ISubjectSpecification and related classes in the full version of Caliburn. I'm not saying that you should switch to Caliburn, but since Screens/Conductors are compatible between the two frameworks, you can take the ISubjectSpecification code and bring it over to CM pretty easily. This might provide you with a few ideas of how to use Screens/Conductors in a bit more MVPish way. In this case, your Screen is a  Presenter and it has a property called Subject which is the ViewModel (or Model).

Sep 21, 2010 at 4:05 PM

Marco

That is very clear, and your English is excellent.

I am not particularly happy with the "ViewModel_MyProperty" for binding. Can I work around this by supplying my own delegate to ViewModelBinder.BindProperties? My plan is to have a Presenter<ViewModel> class with a Subject property exposing the ViewModel. My BindProperties delegate would use this structure to navigate to the ViewModel so that I could just use the property name.

Sep 21, 2010 at 9:08 PM

How did you add the convention for binding property paths with underscore?  I could not even get the "ViewModel_MyProperty" binding to work.

Coordinator
Sep 21, 2010 at 11:52 PM

Do you have the latest source? That was added more recently.

Sep 22, 2010 at 8:23 AM

You can easily customize the conventional binding process to use a different base path for VM properties.
For example, you might tweak ViewModelBinder.BindProperties delegate adding the "Subject_" prefix to each processed element name (this won't fix explicit binding, though).
You may also take a step further and customize ViewModelBinder.Bind. The default behaviour is to set the Action.Target for the view to the corresponding Presenter:

//from ViewModelBinder.Bind
Action.SetTarget(view, viewModel);

To better fit your scenario you might try setting Action.TargetWithoutContext to the Presenter (thus allowing the action messages to get routed to their handler) and the DataContext to the VM exposed by the Presenter:

//viewModel variable will actually contain a reference to your presenter
Action.SetTargetWithoutContext(view, viewModel);
view.DataContext = ((IPresenter)viewModel).Subject;

I assumed that Presenter<ViewModel> implements an interface IPresenter { object Subject {get;} }

This way all databindings would refer to the VM while actions would be routed to Presenter (I didn't actually tested it, but I believe it should work).

Sep 22, 2010 at 2:16 PM

After starting over with a fresh copy of the repository then the underscore binding worked perfectly.  Sorry about that - I thought I had the latest source before but apparently updates in TortoiseHg don't work the way I expected.

Marco's suggestion for customizing the ViewModelBinder.Bind also worked.  In addition to his changes I had to change the type passed in to BindProperties:

ViewModelBinder.BindProperties(namedElements, subjectType);

instead of

ViewModelBinder.BindProperties(namedElements, viewModelType);
Oct 18, 2010 at 4:08 PM

I've just come across CB, and am struggling to follow the suggestions above.   Like Richard I don't like having 'Presenter' functionality in the ViewModel.  I like the VM having bound properties only.  Are there any examples that anyone has done to demonstrate using CM in a more MVVM / MVP fashion?   The samples provided in the documentation tend to show individual features rather than architect samples.  From a beginner's point of view it makes the framework very hard to use.

Richard, maybe you can share what you have learnt?

 

 

Oct 18, 2010 at 4:12 PM

A good sample to see would be a View that on load calls a remote data source (web service) via a Presenter, which on receipt sets the ViewModel and the view refreshes.  Using coroutines to show asynchronous status on the screen.  (i.e. message informing that data is loading, then disappearing once data is displayed).

 

 

Oct 19, 2010 at 12:06 AM
Edited Oct 19, 2010 at 12:06 AM

Some time ago I ported Rob's GameLibrary demo to CM; it demonstrates almost all the features you mentioned.
Have a look at it in my fork: https://hg01.codeplex.com/forks/marcoamendola/caliburnmicromarcoamendolafork
in the /samples/GameLibrary directory.

For a screen executing actions on its initialization, see ShellViewModel.OnInitialize override.

In SearchViewModel.ExecuteSearch you can find an example of coroutines, with the use of a "busy" indicator.

For an example of IResult dealing with asynchronous WCF services, you may have a look at the WebServiceResult class in one of the Caliburn samples: http://caliburn.codeplex.com/SourceControl/changeset/view/55862#1239638

About the MVVM/MVP thing, I suggest you to study the ExploreGameViewModel in the sample.

ExploreGameViewModel holds a reference to a single Game (public GameDTO Game) which is the main "subject" of the screen.
GameDTO contains all bindable data, while ExploreGameViewModel owns some methods (CheckIn/CheckOut) that execute activities on the subject, then call a service; it may also update the GameDTO at the end of server operation (thus refreshing the view).

Let's forget for a moment ExploreGameViewModel name and pretend it is called ExploreGameViewPresenter: you pretty much have the ViewModel (GameDTO) / Presenter (ExploreGameViewPresenter) separation.
I know: ExploreGameViewModel actually has other properties, but you can simply move them in the VM.
Plus, to be fair, GameDTO is... well, a DTO, not a ViewModel; this was mostly done for simplicity: since it is read-only in that context, there was no need to map it to a full featured INotifyPropertyChanged object. 

Does it make sense?

Oct 19, 2010 at 7:23 AM
Hi, many thanks for the response. is there a download link for the first link?



On 19 October 2010 01:06, marcoamendola <notifications@codeplex.com> wrote:

From: marcoamendola

Some time ago I ported Rob's GameLibrary demo to CM; it demonstrates almost all the features you mentioned.Have a look at it in my fork: https://hg01.codeplex.com/forks/marcoamendola/caliburnmicromarcoamendolafork
in the /samples/GameLibrary directory.

For a screen executing actions on its initialization, see ShellViewModel.OnInitialize override.

In SearchViewModel.ExecuteSearch you can find an example of coroutines, with the use of a "busy" indicator.

For an example of IResult dealing with asynchronous WCF services, you may have a look at the WebServiceResult class in one of the Caliburn samples: http://caliburn.codeplex.com/SourceControl/changeset/view/55862#1239638

About the MVVM/MVP thing, I suggest you to study the ExploreGameViewModel in the sample.

ExploreGameViewModel holds a reference to a single Game (public GameDTO Game) which is the main "subject" of the screen.
GameDTO contains all bindable data, while ExploreGameViewModel owns some methods (CheckIn/CheckOut) that execute activities on the subject, then call a service; it may also update the GameDTO at the end of server operation (thus refreshing the view).

Let's forget for a moment ExploreGameViewModel name and pretend it is called ExploreGameViewPresenter: you pretty much have the ViewModel (GameDTO) / Presenter (ExploreGameViewPresenter) separation.
I know: ExploreGameViewModel actually has other properties, but you can simply move them in the VM.
Plus, to be fair, GameDTO is... well, a DTO, not a ViewModel; this was mostly done for simplicity: since it is read-only in that context, there was no need to map it to a full featured INotifyPropertyChanged object. 

Does it make sense?

Read the full discussion online.

To add a post to this discussion, reply to this email (caliburnmicro@discussions.codeplex.com)

To start a new discussion for this project, email caliburnmicro@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com


Oct 19, 2010 at 8:49 AM

From the "Download" link in this page: http://caliburnmicro.codeplex.com/SourceControl/network/Forks/marcoamendola/caliburnmicromarcoamendolafork