View-First Composition?

Topics: Prism v2 - WPF 3.5
Jan 26, 2009 at 9:41 PM
I came across David Hill's blog post (http://blogs.msdn.com/dphill/archive/2008/12/05/ui-composition-patterns.aspx) about a view-centric way of instantiating components, and it looked like exactly what I want to do in my app.  I'd like to be able to instantiate views in XAML and declaratively list the dependencies (such as the ViewModel) to inject. 

David's post had this example:
<UserControl x:Class="UIComposition.Modules.Project.ProjectsListView"
    cal:Presenter.Type="{x:Type UIComposition.Modules.Project.IProjectsListPresenter}">

Is this capability present in the current Prism drop?  If so, where can I find an example of it in the Quickstarts?
Jan 28, 2009 at 5:44 AM
Not within Prism 1.0. An alpha of prism 2.0 should contain this functionality if I'am right: http://www.codeplex.com/CompositeWPF/Release/ProjectReleases.aspx?ReleaseId=21912

Regards
Jan 28, 2009 at 7:02 AM
Edited Jan 28, 2009 at 7:24 AM
Check out the quick starts in v2 drop 9:
- 'View-First' is named 'View Discovery Composition'
- 'Presenter-First' is named 'View Injection Composition'

Cheers,
Jani

Jan 28, 2009 at 7:33 PM
From what I can tell, both View Discovery Composition and View Injection Composition use Presenter-first composition.  The basic process is the same: 

1) The Presenter class uses constructor injection to obtain an instance of its view
2) The module calls Resolve on the Presenter
3) The module register's the Presenter's View with the Region
4) In one way or another, the region displays the View

And of course, all this is done in code.  What I'm asking for is a way to include the child views in the XAML of the parent view.  This would mean that the View class would be the one with constructor injection, and it would obtain an instance of the Presenter class in its constructor.  I've come across two blog posts by the Patterns & Practices team that talk about this (http://blogs.msdn.com/dphill/archive/2008/12/05/ui-composition-patterns.aspxhttp://blogs.msdn.com/erwinvandervalk/archive/2008/10/24/prism-v2-drop-4.aspx), but they refer to Drop 7 and Drop 4 of Prism.  It seems that the team dropped support for this functionality in Drop 9.  Can anybody clear this up for me?  Thanks.
Jan 29, 2009 at 7:03 PM

Hi guys,

What david is describing in his blog post unfortunately is not possible with the upcoming release of Prism.

We talked about this quite a lot - Internally and with our advirors - and decided not to implement something like this.

Our initial idea was to be able to do something like this:
<ContentControl RegionName="MyRegion" ViewType="IMyView">
</ContentControl>

And then also to be able to access interface parameters (like the presenter, or something else) on that interface on the view. However, our advisors were quite strongly opposed to that idea, because it breaks some of the modularity of the system.

Also, specifying the type (or interface) of a view or presenter to load in your view is not easy in silverlight. You have to specify the fully qualified name in a string, because <x:Type IMyViewType> is not supported in Silverlight.

Now, we are supporting ViewDiscovery by registering types against a region name. When a region with that name is displayed, the type of the registered view is created.

What you are describing, createing a view that receives the presenter as a parameter in the constructor is still possible. However, since all the we converted quickstarts from Prism V1 were using the presenter first pattern, we are not demonstrating how to do what you are describing.

So if you do:
 RegionManager.RegisterTypeWithRegion("MyRegion", typeof(MyView));
The view will be created with unity and all dependencies that the view has defined in the constructor will be injected.

Now you also mentioned that you wanted to specify the dependencies in XAML. Please correct me if I'm wrong, but the only reason for that I could think of is if you want to display the same view twice, but with a different TYPE of presenter. Usually, I see it the other way around. Different views using the same presenter to get different representations of the same data & logic.

Now if you really want to specify your dependencies in XAML, it's not impossible, but it requires some serious customization.
1. Create a dependency property for the Region that will host your dependency (for example, a string that will contain the type of the presenter you wish to add)
2. Create a custom regionbehavior that implements IHostAwareRegionBehavior
 2.1 This behavior will monitor the Views collection to see if views are added and removed
 2.2 Retrieve the dependency property value with the presenter type name from the hostcontrol
 2.3 When a view is added, it will create use the presenter typename to create an instance of the presenter and add it to the view. YOu might have to create a common 'IPresenterAware' behavior to allow you to set the presenter on the view.

Hope this helps.

_Erwin 

Jan 29, 2009 at 8:19 PM
Thanks for your thorough reply Erwin.  My reason for wanting to instantiate Views in the XAML was to allow for better designer-developer workflow, one that would involve a minimum of rewriting as code is passed from designer to developer.  This was one of the selling points of WPF: the designer can create all the controls and layout in XAML, and not have to worry about code.  The developer then basically wires up the controls to data and business logic.  What the current CAL patterns force us to do, however, completely demolishes that, and leaves teams with two choices:

1) Designers continue to create the interfaces in Blend/XAML.  When they hand off to the developers, the developers have to do a considerable amount of rewriting of the XAML: they must create Regions wherever a UserControl was called for, and in the Presenter code they must resolve the child control's Presenter and inject the views.  
This path allows designers to work in a way that's easy for them.  They can use an actual design tool (Blend), that allows them to see layout without running the project.  But this leaves the team with two entirely different sets of code.  One that's entirely XAML-based for designers, and one that's largely code-based for developers.  It becomes hard to reconcile changes as the project progresses.

2) The developers work with the designers as they're creating the interface.  We make the project CAL-based from the very beginning.  Developers help the designer create Regions wherever they were going to put a UserControl, and we do all the necessary coding for resolving presenters and injecting views and whatnot.  
The disadvantage here is that designers don't get the advantage of using a design tool, since they must always run the project to see all the pieces come together.  Also, they can't create and include any additional child controls without either having to know how to write the code to write everything up, or they must involve a developer.

I'm probably missing something here, because things can't really be this difficult.  Can you explain how designers and developers work together on your team?

-Amit
Jan 30, 2009 at 10:23 PM
Hi Amit,

Well, the problem again has to do with modularity. The designer of the shell shouldn't make assumptions about the views that are loaded into the regions and the designers of the individual views shouldn't make assumptions about what type of region (or where) it's beying displayed. Because you should be able to recompose your app in a different way.

We have put together some docs on considerations for developers and considerations for designer with regards to modular design. That might help you a bit. For the redesign of the Prism RI, we hired some graphical designers (who were actually more developers with extensive knowlegde of xaml) to work with our developers to update the UI.

I would argue that having both your developers and designers working together would be the ideal approach. As a developer, you can create empty viewmodels that can be used by the designers in Blend to fill the UI with dummy data and allows the designers to test their databinding. While the UI is beying designed, the developers can add the code behind it.  

HOpe that helps
_Erwin