Prism V2 – Drop 4

Today, We have put an other drop of Prism V2 (Composite application guidance for WPF and Silverlight) online. You can download it from here:

https://www.codeplex.com/CompositeWPF/Release/ProjectReleases.aspx?ReleaseId=18750

 

New in Prism V2 - Drop 4

This sprint was mainly focused around UI Composition. We have ported the Region functionality from Prism V1 over so it also works in Silverlight. Then we also addressed a different style of visual composition, we’re calling Top Down composition. I’m going to drill into those composition styles later in this post.

 

Top down vs. Bottom up composition

In the last couple of weeks, we’ve had a lot of discussions around Visual Composition patterns.

Bottom up composition

Prism V1 used a regions to support Bottom Up composition. As a developer, you can define and name regions on your screen. When developing modules, you can use the names of these regions to push views into the regions. At first, we called this “push” based composition, because modules push their views into named regions. The diagram below shows an example of push based composition. We’re also calling this bottom up composition, because lower level modules push their views into the regions of higher level views.

image

Although this composition model allows for a highly decoupled and modular approach to UI development, we received some feedback that in some scenario’s it can be a bit to complex.

Top down composition

With top down composition we took a different approach. Usually, developers are very comfortable with the usage of UserControls. It’s quite common for developers to split up a view into several UserControls to reduce complexity (divide and conquer) and to improve reuse of visual elements. Now it’s quite easy to create controls and place them in different assemblies. However, in order to use those assemblies, the shell has to have a reference to the assemblies that hold the user controls. This goes against the principles of modular development where modules can be versioned, and deployed seperately.

We wanted to allow a model where you can visually compose your application in the same way as using UserControls, but without sacrificing modularity. To do this, we introduced a Top Down composition model:

image

So instead of the shell having a hard reference to the CustomerModule and putting a CustomerView directly on the ShellView, you put a ContentControl in the place where you want the user control. Then you use an attached property ViewType to specify what kind of View you want to display here, by specifying the interface of the view to display. The view interfaces can be defined in a seperate (Interface) module or in the shell.

When a module get’s initialized, it typically registers it’s views to the DI container. For example, the CustomerModule will tell the container that it can provide an implementation of the ICustomerView, because it registers the CustomerView type with the ICustomerView interface. Now after module initialization, the ShellView will ask the DI container for an implementation of ICustomerView. This will of course return the CustomerView, so it can then be shown in the ContentControl. Essentially, the ContentControl on the ShellView is pulling the CustomerView in from the CustomerModule, without having a direct reference to that module. We are calling this “Top Down” composition, because the Higher level modules define which views are displayed where.

This is an example (from the TopDownCompositionQuickstart) on how you specify a view that’s pulled into the shell in XAML:

 <ContentControl 
    Regions:ContentController.ViewType=
         "TopDownComposition.Modules.Employee.IEmployeesListView, EmployeeModule.Silverlight, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

You might notice 2 things:

1.
The viewtype is a string
At first we wanted to use the type of the interface directly. Unfortunately, this doesn’t work in Silverlight, because you cannot create types in XAML, because {x:Type} doesn’t work. But working with strings isn’t too bad. We’re planning to make the resolving logic pluggable. This way, you could for example use logical names, exported by your modules, to identify and retrieve the views. In fact, the MEF framework also works like that.

2.
The viewtype is a really long string
To make working with those really long strings a bit more bearable, we’re also thinking of building a custom type resolver. Since 99.9% of the times the full typename (Namespace.TypeName) is unique, you can get away with just specifying that and let the framework figure out which assembly the type came from.

We’re also considering moving the View resolving functionality from the ContentController to the RegionManager. Even though technically this has nothing to do with regions, conceptually it’s very similar. A region specifies where you want to display visual elements from other modules. In the top down approach, you specify the content via it’s interface and in the bottom up approach you give it a name so others can push views into it. But it’s still a placeholder for views.

Conclusion

Hopefully you’ve found this post useful in explaining what we’re building. As always, we are very open to feedback. If you don’t like something we do, please tell us! Also if you do like something, tell us that as well! It might just prevent us from changing something you are already happy with :)

Comments

  • Anonymous
    October 25, 2008
    PingBack from http://www.alvinashcraft.com/2008/10/25/dew-drop-october-25-2008/

  • Anonymous
    October 27, 2008
    Hi Erwin.  I have a question and a comment. First, will you be able at runtime to change out the view?  If so, how? Second, it would seem like defining the view interface in the shell would defeat the purpose of decomposition.  Thus, I would have said the view interface should be in a separate assembly that is shared by the shell and the module.

  • Anonymous
    October 27, 2008
    Hi Norman, Thanks for your reply. I've added a new blogpost to answer your first question. With regards to your remark. I agree that it would make more sense to put the interface in a seperate assembly. We were currently focussing more on getting it to actually work, but we'll put it on the backlog. thanks for pointing it out. -Erwin