Exploding elements, MVVM, Prism, Unity, RIA Service and offline apps!
Well the Tech.Ed time of year is over and let me tell you I had a fantastic time!
I was lucky enough to be asked to present a number of sessions in both Australia and New Zealand:
Going Deeper in Silverlight 3 (AU WEB309, NZ WUX301)
Architectural Considerations for Silverlight (AU ARC401, NZ ARC301)
Live Meeting stream of Going Deeper in Silverlight 3
Silverlight Birds of a Feather Lunch
A panel discussion on Rich vs Reach in Australia
A panel discussion on Designer and Developer workflow in New Zealand
All in all it was a massive fortnight and I’m only starting to catch up with the real world now!
As promised I’m releasing the code from my talks here.
The Architectural Considerations demo code should just start… but the Going Deeper code may need some “jiggling” as it is using IIS to run (so you can start and stop IIS to see server ping working).
TechEd 09 Australia and New Zealand Demo Code
Make sure you run VS as elevated
Once the IIS site has been created, go to IIS settings, create a new app pool. Run this app pool as local system (never do this in production!!). Make sure you set your site to use the new app pool. Without this the database would not load for me
Ensure you set the web project and sample ASPX file as start up
Both my talks take the real world approach – I didn’t want to just talk about stuff you can easily find by searching the ‘net – I wanted to show methods that I would employ in a real world application if asked to use these features.
The Architecture talk also concentrated heavily on how you can set up your project to make it nice and easy for developers to extend and maintain the application using Prism and MVVM.
This said, keep in mind this *is* demo code :)
Going Deeper in Silverlight 3
This session was split in to two sections – first we talked about some of the UI enhancements in Silverlight 3 then on to some of the more business style enhancements.
For perspective 3d and plane projection I demonstrated how to create a control based on ItemsControl to convert a standard boring old items list in to a fully 3d tag cloud complete with mouse interaction to move the items around the screen.
This can be found under Controls/3D/TagCloud and TagCloud item.
The ItemsControl (TagCloud) creates the item wrapper control (TagCloudItem). This is required for all items controls. For comparison ListBox control uses ListBoxItem <- each item in the list is wrapped in in a ListBoxItem, to which the DataTemplate is applied. A few methods are overridden in TagCloud, including GetContainerForItemOverride (create the TagCloudItem), IsItemItsOwnContainerOverride (to check that the user didn’t add TagCloudItems to the ItemsSource of the TagCloud) and PrepareContainerForItemOverride (which isn’t used, but gives you the chance to do something with the TagCloudItem and the data that will be applied to it).
The TagCloudItem is then responsible for making itself 3d. This is a great approach because you can template each item like normal, but the TagCloudItem brings the extra 3d behaviour – staying completely away from template modification and it will work straight out of the box when inserted in to a page.
The TagCloud is applied in MainPage.xaml.
After a quick introduction to animation easing in Blend, I demonstrated how to create a custom animation easing function. The function is called RandomEase and can be found in Controls/Easing/RandomEase.cs.
This easing function basically takes any animation and randomises it – the best way to see this in action is to just run the app, 1000 words and all that. You will see my blog url in the bottom right of the app going crazy :)
The easing function is applied to the animations in MainPage.xaml in the UserControl.Resources section.
Behaviours, WritableBitmap and Perspective 3D
To demonstrate behaviours I created a special behavior called SuperVortex (Controls/Behavior/SuperVortex). There are two versions of this control, one which targets my custom control called TimerContentControl and one which can target any panel (Canvas, Grid etc).
The TimerControlControl is a cool little control I created which has a couple of states – one for when it’s content is null and one for when it’s content is set. This control is then bound to a property in the ViewModel, and when that property changes the control switches states allowing it to be shown on the screen. The control will show for a number of seconds before timing out the hiding itself again.
The SuperVortex behavior is then added to this control. A few seconds after the TimerContentControl is shown the SuperVortex kicks in and breaks the control in to a number of separate tiles, makes them spin around the screen before disappearing off in to the ether.
It achieves this by calculating a range of 50×50 tiles, then using the WritableBitmap control it splits it up by taking multiple snapshots of the control. Each snapshot uses a TranslateTransform to position itself to take a snapshot of the control in the right spot, creating a 50×50 tile. This snapshot is then added to a dynamically created image which is in turn added to the page (once again using another translate transform to reposition it where the original snapshot was crated).
Once all the tiles are created and overlaid, the original control is hidden. PlaneProjection is then used to spin the image tiles around of off the screen.
OOB and Network Detection
This is my favourite part of the talk – it revolves around using real world network detection, a service manager, a service locator and dependency injection to create a nice little loosely coupled network dection and management of online and offline services solution.
All data access in the application is performed through “repositories”. A repository is a small class which contains all the operations required to get data from the server. Each repository only contains methods to get a particular entity type. In this case we are getting Player entities from the server, so our repositories are called PlayerRespoistory. There are two PlayerRepositories, one for Online and for Offline.
The PlayerRepositories implement IPlayerRepository. When using a repository in code the app always references IPlayerRepository.
It all starts with the NetworkManagementService (Model\AppServices\NetworkStatusManager.cs). This service starts with the application (it implements IApplicationService). It then hooks up to the network changed events. Then it checks to see if the network adaptor is available. If it isn’t then it sets itself to be offline (firing events too). If the network adaptor is available, it will start a timer which will ping the server (using .NET RIA Services) to see if it is available. It then fires events based on whether the server is there or not.
These network events are detected by the ServiceManager. The ServiceManager is provided an instance of the Unity IOC Container. The Unity IOC container allows you to configure which concrete class will be resolved at a given time. As the network state changes from NetworkManagementService, the ServiceManager changes Unity to resolve a different version of the PlayerRepository by configuring IPlayerRepository to resolve to the online or offline version.
The ViewModel then asks the ServiceLocator for the IPlayerRepository. The ServiceLocator also uses Unity – this time to resolve the dependency. The ServiceLocator can just ask Unity to resolve the IPlayerRepository without having to know about the NetworkManagementService or the ServiceManager (i.e. it is loosely coupled). This is great as it makes it very easy to alter the behavior of the network and service management stuff without the rest of the application worrying about it.
Online and Offline
The two repositories operate different to each other. They both have to same methods to please the IPlayerRepository interface, but internally they do different things. First, the online version will serialise the retrieved entities to Isolated Storage for later retrieval, and the offline version will check for these saved entities, and deserialise them if available.
Once the application is running if you stop IIS the system will automatically switch between online and offline versions of the repositories, allowing offline data access.
Architectural Considerations for Silverlight
In this talk I (with Mahesh in Australia!) demonstrated more real world scenarios, this time around Prism (Composite UI) and MVVM (Model-View-ViewModel).
This talk takes the approach of creating good Silverlight architecture around these concepts to assist developers in working on the code on a day to day basis. It hides the complexity of using MVVM and Prism in a set of self documenting base classes. Developers that use these classes will find it very easy to create new Prism modules and ViewModels.
First up the Prism stuff. I demonstrated how easy it can be to create a new module with Prism with a simple Module base class, ViewModel base class and an interface for your views (called IView). The ViewModelBase base class takes the IView in its constructor and then using this interface is able to apply itself to the DataContext of the View (through the only method, ApplyModel). So now the ViewModelBase class will automatically do View hookup for us.
Then you create a new Prism module class and base it on ModuleBase. This class has one abstract method called Initialize. It also requires IUnityContainer and IRegionManager in its constructor (these are used by the base class).
In the Initialize method we call Register<ViewType, ViewModelType>(“RegionName”);. This makes it very easy for developers to create a view and view model, have the view model married up to the view and then register them in to a region. It uses Unity to create the instances (check out the Register method to see how). Because of the generic method, it is very self documenting and developers will be able to follow this without any extra instruction.
For the last part of this talk I demonstrated a series of ViewModel base classes that I’ve been working on and improving for a while now.
The basic idea is that I wanted to create ViewModel base classes to encapsulate CRUD operations for both single entities and lists of entities.
This view model class has all the commands and operations required to edit a single entity. It is based on ViewModelBase so can do to auto view model hookup talked about above. This class contains Commands which can be bound to buttons in the UI to allow the Save and Cancel edit of entities. What’s cool here is that using RIA Services, cancel will automatically roll back the edit of the entity. It also contains things like validation, logs errors in to an ObservableCollection for easy binding to the UI etc.
This view model allows for the editing of multiple items in a list. It is based on EditableEntityViewModelBase. This means that it can be used to edit the collection and also single items in the collection.
What’s cool here is that you can add new items, edit existing items, then click cancel – the new items will be removed again and the existing items will be reverted.
This view model is based on EditableCollectionViewModel. It basically only has to get a list of the characters from the repository, other than this all other functionality is gained from the base classes.
As the base classes are once again generic they are self documenting to the developer – the developer cannot implement these classes wrong without getting a compiler error.
The edit screens use the Silverlight ToolKits DataForm. This control allows you to create edit forms for entities, complete with validation. The problem is that when the save or cancel buttons are pressed you need a way to inform the ViewModel that something happened. You don’t want to create any code behind in your view to do this or you are breaking the MVVM pattern.
To solve this I created a custom command handler that hooks up to the DataForm and allows commands to be bound that will fire when the DataForm Saves or Cancels. These commands are then bound up to the Commands from EditableEntityViewModel base… a nice solution all round.
As always if you have any questions or comments please don’t hesitate to ping me a comment, or contact me on twitter (@jakkaj).