A while ago, I put an example application on my blog on how to build an outlook style application.
The last couple of weeks, I’ve been working on a new version of this app. I’ve done some bugfixes, but also included support for opening use cases in a popup window. It’s turning out to be quite an advanced demo of what’s possible with Prism. But while I’m playing with it, I can’t help but be amazed with the things I can push Prism into doing :)
<Outlook style app>
You will need the following references to make the solution work:
So there are a couple of things I didn’t explain in my previous blog:
So here goes:
I’m a big van of ViewModel first development. So what does that mean?
There are a couple of big advantages to this approach:
I wanted to be able to put ViewModels into my regions and to have some code that would provide the visualization onto it. So the code I want to be able to write is:
// 1: Setup visualizations (typically in Module.Initialize) // Whenever an EmailMainViewModel is displayed, visualize it with an EmailMainView modelVisualizationRegistry.Register<EmailMainViewModel, EmailMainView>(); // 2: Add ViewModels to region (view discovery, view injection or any other method) region.Add(new EmailMainViewModel());
If you’re interested in how I built the ViewModel First code? here it is:
The first step into creating the view model first appraoch was to create a ModelVisualizer class. The reason for this was: "The prism region adapters will put the content of the regions directly into the control that hosts the region (for example, a contentcontrol). There is no extensionpoint to sit in between that.
So I created something that I could put in a region, that would hold BOTH the View and the ViewModel. It would be the glue between the view and the viewmodel and:
The following diagram explains my ModelVisualizer.
The ModelVisualizer IS a ContentControl. So it can be placed inside the Visual Tree. It will set the View as the content. It will also set the ViewModel as the datacontext of the view (so the view can bind to all the information in the ViewModel). Lastly, the IModelVisualizer implements the IRegionContextAware and IActiveAware interfaces, and will synchronize these interfaces with the View and ViewModel if they implement the interfaces.
The ModelVisualizer worked great. However, it demanded that all my code knew about the ModelVisualizer. I didn’t want to do that, because I wanted to make it implicit. There were some issues with that though, because due to the current implementation the region adapters, I didn’t have an extension point to create my visualizations implicitly. I couldn’t change the type of region that was created by adapters and I couldn’t change how the adapters set the content of the region to the hostcontrol. But I solved that with a little trick, that I call my VisualizingRegion.
The trick was: while I couldn’t change what type of region was being created, I could control what type of region was registered to the RegionManager (because there is a regionbehavior that does the registration. So I just wrapped the Region that was created by the regionadapters in my own region (the visualizing region) and registered my own visualizing region to the regionmanager.
The only way a consumer can get access to the Region is through the RegionManager, so that solved the problem :)
In Prism V2, we introduced the concept of RegionContext. The RegionContext is a way that a view that hosts a region can share some of it’s information with any childviews that are loaded into it’s region. While I really liked the concept of RegionContext, I didn’t really like the implementation of it.
So I created the IRegionContextAware interface. It has one property (the regioncontext as an ObservableObject) and the RegionContextAwareRegionBehavior that would sync the context of the region with the RegionContextAware properties.
One thing I thought was an interesting challenge was opening a viewmodel in a (non modal) popup. So why would this be challenging:
The code I wanted to be able to write is:
1: // Create an UseCase to write new email messages
2: NewEmailUseCase newEmailUseCase = ApplicationModel.CreateObjectInScopedRegionManager<NewEmailUseCase>();
3:
4: // Add some data to the Email message use case (in this case, a blank new email)
5: newEmailUseCase.Message = new EmailMessage();
6:
7: // Show the email (in a popup, but the consumer doesn't know that)
8: ApplicationModel.ShowUseCase(newEmailUseCase);
The problem with opening several instances of the same popup is: Regions are identified by name in the regionmanager. If you have several popups of the same type open, each popup needs it’s own RegionManager, or else the region names will collide. In my scenario, I decided that the Popup has most of the same region names as the main shell. That way, any ViewModel or use case could be loaded in either the popup or the main window.
Ok, so i need to create a scoped regionmanager. That’s not to hard, just do: RegionManager.CreateRegionManager() and you have one. However, I wanted the consuming code NOT to have to think about this. It should be blissfully ignorant about the fact that it’s in a scoped regionmanager or not.
Since all most of my objects are created by a DI Container, and it injects all of the dependencies to my object, I decided to use that to solve this problem. So I created a scoped Container and registered the scoped regionmanager with that. Then I created my use case from the newly created scoped container, and if it needs a regionmanager, it would automatically get the scoped regionmanager. Pretty neat huh.
So schematic, that looks like this:
So when the use case (in green) get’s created, it and it’s dependencies would get the scoped regionmanager injected. Without knowing about the scoped containers or scoped regionmanager.
Adding the use case to a popup (in the application model) works like this:
As you can see, there are quite a lot of moving bits for showing a use case into a popup. Of course, it would have been A LOT easier to give ‘your code’ (an other use case or something) the knowledge that a view can be opened in popup.
If you look at my viewmodels, you’ll see that I make use of the ObservableObject a LOT. It’s a very simple object, one that just takes a type and wraps it in a INotifyPropertyChanged. The nice thing about this is, that I don’t have to add any INotifyPropertyChanged code in my ViewModels anymore. That makes it soooo much easier to do 2 way databinding in WPF.
The only problem is, that to get to the value, you often have to do: viewModel.MyProperty.Value to get to the actual value of MyProperty. But I thought that’s worth it since now I don’t have to write INotifyPropertyChanged code for my properties anymore.
Like I mentioned, before, this outlook style app has become quite an advanced demo of what’s possible with Prism. But I hope it gives you some idea’s on what’s possible with it. I’m also in the process of creating a video walkthrough of this application. But I’ll let you know when that’s done!
Keep practicing!
_Erwin
[UPDATE]
If you get an System.Threading.SynchronizationLockException from Unity: Don’t worry! I had turned on ‘break on all exceptions’ so the debugger is also breaking on these handled exceptions. Just continue and the app will run fine, or change that debug setting.