Project Description

Designed to aid in the development of WPF and Silverlight applications, Caliburn implements a variety of UI patterns for solving real-world problems. Patterns that are enabled by the framework include MVC, MVP, Presentation Model (MVVM), Commands and Application Controller.

Goals

  • Support building WPF/SL application that are TDD friendly.
  • Implement functionality for simplifying various UI design patterns in WPF/SL. These patterns include MVC, MVP, Presentation Model (MVVM), Commands, etc.
  • Ease the use of a dependency injection container with WPF/SL.
  • Simplify or provide alternatives to common WPF/SL related tasks.
  • Provide solutions to common UI architecture problems.

Want a smaller, simpler framework with 90% of the features and power? Check out Caliburn.Micro. Want to stick with the big guns? Get the Caliburn V1.1 RTW now and have a look at the documentation.

 .NET & Funky Fresh News Feed 
Saturday, August 21, 2010  |  From .NET & Funky Fresh

Before our WP7 detour, we were deep in the thick of Actions. I mentioned that there was one more compelling feature of the Actions concept called Coroutines. If you haven’t heard that term before, here’s what wikipedia* has to say:



In computer science, coroutines are program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, iterators,infinite lists and pipes.


Here’s one way you can thing about it: Imagine being able to execute a method, then pause it’s execution on some statement, go do something else, then come back and resume execution where you left off. This technique is extremely powerful in task-based programming, especially when those tasks need to run asynchronously. For example, let’s say we have a ViewModel that needs to call a web service asynchronously, then it needs to take the results of that, do some work on it and call another web service asynchronously. Finally, it must then display the result in a modal dialog and respond to the user’s dialog selection with another asynchronous task. Accomplishing this with the standard event-driven async model is not a pleasant experience. However, this is a simple task to accomplish by using coroutines. The problem…C# doesn’t implement coroutines natively. Fortunately, we can (sort of) build them on top of iterators.


There are two things necessary to take advantage of this feature in Caliburn.Micro: First, implement the IResult interface on some class, representing the task you wish to execute; Second, yield instances of IResult from an Action.** Let’s make this more concrete. Say we had a Silverlight application where we wanted to dynamically download and show screens not part of the main package. First we would probably want to show a “Loading” indicator, then asynchronously download the external package, next hide the “Loading” indicator and finally navigate to a particular screen inside the dynamic module. Here’s what the code would look like if your first screen wanted to use coroutines to navigate to a dynamically loaded second screen:


using System.Collections.Generic;
using System.ComponentModel.Composition;

[Export(typeof(ScreenOneViewModel))]
public class ScreenOneViewModel
{
public IEnumerable<IResult> GoForward()
{
yield return Loader.Show("Downloading...");
yield return new LoadCatalog("Caliburn.Micro.Coroutines.External.xap");
yield return Loader.Hide();
yield return new ShowScreen("ExternalScreen");
}
}

First, notice that the Action “GoForward” has a return type of IEnumerable<IResult>. This is critical for using coroutines. The body of the method has four yield statements. Each of these yields is returning an instance of IResult. The first is a result to show the “Downloading” indicator, the second to download the xap asynchronously, the third to hide the “Downloading” message and the fourth to show a new screen from the downloaded xap.  After each yield statement, the compiler will “pause” the execution of this method until that particular task completes. The first, third and fourth tasks are synchronous, while the second is asynchronous.  But the yield syntax allows you to write all the code in a sequential fashion, preserving the original workflow as a much more readable and declarative structure. To understand a bit more how this works, have a look at the IResult interface:


public interface IResult
{
void Execute(ActionExecutionContext context);
event EventHandler<ResultCompletionEventArgs> Completed;
}

It’s a fairly simple interface to implement. Simply write your code in the “Execute” method and be sure to raise the “Completed” event when you are done, whether it be a synchronous or an asynchronous task. Because coroutines occur inside of an Action, we provide you with an ActionExecutionContext useful in building UI-related IResult implementations. This allows the ViewModel a way to declaratively state it intentions in controlling the view without having any reference to a View or the need for interaction-based unit testing. Here’s what the ActionResultContext looks like:


public class ActionExecutionContext
{
public ActionMessage Message;
public FrameworkElement Source;
public object EventArgs;
public object Target;
public DependencyObject View;
public MethodInfo Method;
public Func<bool> CanExecute;
public object this[string key];
}

And here’s an explanation of what all these properties mean:


  • Message – The original ActionMessage that caused the invocation of this IResult.
  • Source – The FrameworkElement that triggered the execution of the Action.
  • EventArgs – Any event arguments associated with the trigger of the Action.
  • Target – The class instance on which the actual Action method exists.
  • View – The view associated with the Target.
  • Method – The MethodInfo specifying which method to invoke on the Target instance.
  • CanExecute – A function that returns true if the Action can be invoked, false otherwise.
  • Key Index: A place to store/retrieve any additional metadata which may be used by extensions to the framework.

Bearing that in mind, I wrote a naive Loader IResult that searches the VisualTree looking for the first instance of a BusyIndicator to use to display a loading message. Here’s the implementation:


using System;
using System.Windows;
using System.Windows.Controls;

public class Loader : IResult
{
readonly string message;
readonly bool hide;

public Loader(string message)
{
this.message = message;
}

public Loader(bool hide)
{
this.hide = hide;
}

public void Execute(ActionExecutionContext context)
{
var view = context.View as FrameworkElement;
while(view != null)
{
var busyIndicator = view as BusyIndicator;
if(busyIndicator != null)
{
if(!string.IsNullOrEmpty(message))
busyIndicator.BusyContent = message;
busyIndicator.IsBusy = !hide;
break;
}

view = view.Parent as FrameworkElement;
}

Completed(this, new ResultCompletionEventArgs());
}

public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

public static IResult Show(string message = null)
{
return new Loader(message);
}

public static IResult Hide()
{
return new Loader(true);
}
}

See how I took advantage of context.View? This opens up a lot of possibilities while maintaining separation between the view and the view model. Just to list a few interesting things you could do with IResult implementations: show a message box, show a VM-based modal dialog, show a VM-based Popup at the user’s mouse position, play an animation, show File Save/Load dialogs, place focus on a particular UI element based on VM properties rather than controls, etc. Of coarse, one of the biggest opportunities is calling web services. Let’s look at how you might do that, but by using a slightly different scenario, dynamically downloading a xap:


using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;

public class LoadCatalog : IResult
{
static readonly Dictionary<string, DeploymentCatalog> Catalogs = new Dictionary<string, DeploymentCatalog>();
readonly string uri;

[Import]
public AggregateCatalog Catalog { get; set; }

public LoadCatalog(string relativeUri)
{
uri = relativeUri;
}

public void Execute(ActionExecutionContext context)
{
DeploymentCatalog catalog;

if(Catalogs.TryGetValue(uri, out catalog))
Completed(this, new ResultCompletionEventArgs());
else
{
catalog = new DeploymentCatalog(uri);
catalog.DownloadCompleted += (s, e) =>{
if(e.Error == null)
{
Catalogs[uri] = catalog;
Catalog.Catalogs.Add(catalog);
catalog.Parts
.Select(part => ReflectionModelServices.GetPartType(part).Value.Assembly)
.Where(assembly => !AssemblySource.Instance.Contains(assembly))
.Apply(x => AssemblySource.Instance.Add(x));
}
else Loader.Hide().Execute(context);

Completed(this, new ResultCompletionEventArgs {
Error = e.Error,
WasCancelled = false
});
};

catalog.DownloadAsync();
}
}

public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
}

In case it wasn’t clear, this sample is using MEF. Furthermore, we are taking advantage of the DeploymentCatalog created for Silverlight 4.  You don’t really need to know a lot about MEF or DeploymentCatalog to get the takeaway. Just take note of the fact that we wire for the DownloadCompleted event and make sure to fire the IResult.Completed event in its handler. This is what enables the async pattern to work. We also make sure to check the error and pass that along in the ResultCompletionEventArgs. Speaking of that, here’s what that class looks like:


public class ResultCompletionEventArgs : EventArgs
{
public Exception Error;
public bool WasCancelled;
}

Caliburn.Micro’s enumerator checks these properties after it get’s called back from each IResult. If there is either an error or WasCancelled is set to true, we stop execution. You can use this to your advantage. Let’s say you create an IResult for the OpenFileDialog. You could check the result of that dialog, and if the user canceled it, set WasCancelled on the event args. By doing this, you can write an action that assumes that if the code following the Dialog.Show executes, the user must have selected a file. This sort of technique can simplify the logic in such situations. Obviously, you could use the same technique for the SaveFileDialog or any confirmation style message box if you so desired. My favorite part of the LoadCatalog implementation shown above, is that the original implementation was written by a CM user! Thanks janoveh for this awesome submission! As a side note, one of the things we added to the CM project site is a “Recipes” section. We are going to be adding more common solutions such as this to that area in the coming months. So, it will be a great place to check for cool plugins and customizations to the framework.***


Another thing you can do is create a series of IResult implementations built around your application’s shell. That is what the ShowScreen result used above does. Here is its implementation:


using System;
using System.ComponentModel.Composition;

public class ShowScreen : IResult
{
readonly Type screenType;
readonly string name;

[Import]
public IShell Shell { get; set; }

public ShowScreen(string name)
{
this.name = name;
}

public ShowScreen(Type screenType)
{
this.screenType = screenType;
}

public void Execute(ActionExecutionContext context)
{
var screen = !string.IsNullOrEmpty(name)
? IoC.Get<object>(name)
: IoC.GetInstance(screenType, null);

Shell.ActivateItem(screen);
Completed(this, new ResultCompletionEventArgs());
}

public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

public static ShowScreen Of<T>()
{
return new ShowScreen(typeof(T));
}
}

This bring up another important feature of IResult. Before CM executes a result, it passes it through the IoC.BuildUp method allowing your container the opportunity to push dependencies in through the properties. This allows you to create them normally within your view models, while still allowing them to take dependencies on application services. In this case, we depend on IShell. You could also have your container injected, but in this case I chose to use the IoC static class internally. As a general rule, you should avoid pulling things from the container directly. However, I think it is acceptable when done inside of infrastructure code such as a ShowScreen IResult.


I hope this gives some explanation and creative ideas for what can be accomplished with IResult. Be sure to check out the sample application attached. There’s a few other interesting things in there as well.


* When I went to look up the “official” definition on wikipedia I was interested to see what it had to say about implementations in various languages. Scrolling down to the section on C#…Caliburn was listed! Fun stuff.


** You can also return a single instance of IResult without using IEnuermable<IResult> if you just want a simple way to execute a single task.


*** If you want a sample of a truly awesome plugin we will be adding to the recipes section soon, check this out!

Sunday, August 08, 2010  |  From .NET & Funky Fresh

Hopefully, previous articles have you up to speed on what Caliburn.Micro is, its basic configuration, and how to take advantage of a few of its features. In this part, I want to talk about some WP7 specifics issues. It’s unfortunate that I have to call out WP7, but your going to find that while you may be an experienced WPF or Silverlight developer, that doesn’t make WP7 development a snap. Microsoft still has a long ways to go in making “three screens and the cloud” a reality. The new features in Caliburn.Micro are specifically designed to address some of the shortcomings in WP7, particularly around Navigation (with ViewModels and Screen Activation), Tombstoning and Launchers/Choosers.


 


Bootstrapper


Let’s start by getting our application configured correctly. In previous parts we began by creating a bootstrapper and adding it to our Application.Resources. We do the same thing on WP7, but we inherit our bootstrapper from the PhoneBootstrapper class. Here’s how the bootstrapper for our WP7 sample application looks:


using System;
using System.Collections.Generic;
using Microsoft.Phone.Tasks;

public class HelloWP7Bootstrapper : PhoneBootstrapper
{
PhoneContainer container;

protected override void Configure()
{
container = new PhoneContainer();

container.RegisterSingleton(typeof(MainPageViewModel), "MainPageViewModel", typeof(MainPageViewModel));
container.RegisterSingleton(typeof(PageTwoViewModel), "PageTwoViewModel", typeof(PageTwoViewModel));
container.RegisterPerRequest(typeof(TabViewModel), null, typeof(TabViewModel));

container.RegisterInstance(typeof(INavigationService), null, new FrameAdapter(RootFrame));
container.RegisterInstance(typeof(IPhoneService), null, new PhoneApplicationServiceAdapter(PhoneService));

container.Activator.InstallChooser<PhoneNumberChooserTask, PhoneNumberResult>();
container.Activator.InstallLauncher<EmailComposeTask>();
}

protected override object GetInstance(Type service, string key)
{
return container.GetInstance(service, key);
}

protected override IEnumerable<object> GetAllInstances(Type service)
{
return container.GetAllInstances(service);
}

protected override void BuildUp(object instance)
{
container.BuildUp(instance);
}
}

For WP7, there are less IoC container options available. In this case, I’ve written a simple container myself. You can get the full code for SimpleContainer in the Recipes section of the CM Documentation. Additionally, I inherited from SimpleContainer to create PhoneContainer, which just adds some custom activation logic related to Launchers/Choosers. We’ll dig into that a bit later. The most important thing to note in this code is the use of PhoneBootstrapper and the registrations of two services: INavigationService, which wraps the RootFrame and IPhoneService, which wraps the native PhoneService. The RootFrame and PhoneService are created by the PhoneBootstrapper and added to the appropriate places, so you can keep your App.xaml and App.xaml.cs files clean. Here’s what they should look like:


<Application x:Class="Caliburn.Micro.HelloWP7.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Caliburn.Micro.HelloWP7">
<Application.Resources>
<local:HelloWP7Bootstrapper x:Key="bootstrapper" />
</Application.Resources>
</Application>

using System.Windows;

public partial class App : Application
{
public App()
{
InitializeComponent();
}
}

 


INavigationService


Let’s dig into what the FrameAdapter implementation of INavigationService does for you. First, you should know that WP7 enforces a View-First approach to UI at the platform level. Like it or not (I don’t) the platform is going to create pages at will and the Frame control is going to conduct your application thusly. You don’t get to control that and there are no extensibility points, unlike the Silverlight version of the navigation framework. Rather than fight this, I’m going to recommend embracing the View-First approach for Pages in WP7, but maintaining a Model-First composition strategy for the sub-components of those pages. In order to support the View-First approach, I’ve enabled the FrameAdapter to hook into the native navigation frame’s functionality and augment it with the following behaviors:


When Navigating To a Page


  1. Use the new ViewModelLocator to conventionally determine the name of the VM that should be attached to the page being navigated to. Pull that VM by key out of the container.
  2. If a VM is found, use the ViewModelBinder to connect the Page to the located ViewModel.
  3. Examine the Page’s QueryString. Look for properties on the VM that match the QueryString parameters and inject them, performing the necessary type coercion.
  4. If the ViewModel implements the IActivate interface, call its Activate method.

When Navigating Away From a Page


  1. Detect whether the associated ViewModel implements the IGuardClose interface.
  2. If IGuardClose is implemented and the app is not being tombstoned or closed, invoke the CanClose method and use its result to optionally cancel page navigation.*
  3. If the ViewModel can close and implements the IDeactivate interface, call it’s Deactivate method.
  4. If the application is being tombstoned or closed, pass “true” to the Deactivate method indicating that the ViewModel should permanently close.

The behavior of the navigation service allows the correct VM to be hooked up to the page, allows that VM to be notified that it is being navigated to (IActivate), allows it to prevent navigation away from the current page (IGuardClose) and allows it to clean up after itself on navigation away, tombstoning or normal “closing” of the application (IDeactivate). All these interfaces (and a couple more) are implemented by the Screen class. I haven’t discussed Screens and Conductors yet, but you can get started taking advantage of them with just the simple information I have provided. If you prefer not to inherit from Screen, you can implement any of the interfaces individually of coarse. They provide a nice View-Model-Centric, testable and predictable way of responding to navigation without needing to wire up a ton of event handlers or write important application flow logic in the page’s code-behind. Simply follow the same naming conventions for View/ViewModels as normal, plug the FrameAdapter into your IoC container and implement whatever interfaces you care about on your VMs.


 


IPhoneService


There’s really not much to say about this. I abstracted an interface for the built-in PhoneApplicationService and created a decorator. This makes it easy for VMs to take a dependency on the functionality without being coupled to the actual phone service. I didn’t add any additional behavior.


 


Now that we have the basic service explanations over with, let’s create some Views and ViewModels to get our navigation working and to demonstrate a few other features. The default WP7 template creates a MainPage.xaml for you and configures the application to use that as its default starting point. We’ll use that, but change the Xaml to this:


<phone:PhoneApplicationPage x:Class="Caliburn.Micro.HelloWP7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0"
Margin="24,24,0,12">
<TextBlock Text="WP7 Caliburn.Micro"
Style='{StaticResource PhoneTextNormalStyle}' />
<TextBlock Text='Main Page'
Margin='-3,-8,0,0'
Style='{StaticResource PhoneTextTitle1Style}' />
</StackPanel>

<Grid Grid.Row='1'>
<Button x:Name='GotoPageTwo'
Content='Goto Page Two' />
</Grid>
</Grid>
</phone:PhoneApplicationPage>

The only noteworthy thing I have done here is to add a single Button to the page in order to demonstrate navigation. Here’s what the MainPageViewModel looks like:


using System;

public class MainPageViewModel
{
readonly INavigationService navigationService;

public MainPageViewModel(INavigationService navigationService)
{
this.navigationService = navigationService;
}

public void GotoPageTwo()
{
navigationService.Navigate(new Uri("/PageTwo.xaml?NumberOfTabs=5", UriKind.RelativeOrAbsolute));
}
}

Here’s what it would look like if we could run it at this point:


PageOne


It’s pretty simple, but there are a few things worth mentioning. The first is that our INavigationService is being injected through the constructor. This will happen when we navigate to the page and the VM is conventionally resolved and wired up. In this case we haven’t implemented any interfaces or inherited from any base classes. We don’t really care about lifecycle. Take a look at the GotoPageTwo method (conventionally wired to the big button). We are using the INavigationService to tell the phone to go to PageTwo.xaml. Remember the query string and have a look at the ViewModel for PageTwo:


using System;
using System.Collections.Generic;
using System.Linq;

[SurviveTombstone]
public class PageTwoViewModel : Conductor<IScreen>.Collection.OneActive
{
readonly Func<TabViewModel> createTab;

public PageTwoViewModel(Func<TabViewModel> createTab)
{
this.createTab = createTab;
}

public int NumberOfTabs { get; set; }

protected override void OnInitialize()
{
Enumerable.Range(1, NumberOfTabs).Apply(x =>{
var tab = createTab();
tab.DisplayName = "Item " + x;
Items.Add(tab);
});

ActivateItem(Items[0]);
}
}

The value of the the QueryString parameter “NumberOfTabs” is going to be injected into the property of the same name on the ViewModel. The OnInitialize method is part of the Activation lifecycle I mentioned above. If you notice in the bootstrapper’s configuration, PageTwoViewModel is a Singleton. OnInitialize will be called the first time this page is navigated to, not on any subsequent times, while OnActivate will be called every time this page is navigated to. These are properties of the Screen class from which this ViewModel ultimately inherits. Basically, all this method does is create a parameterized number of child ViewModels (TabViewModel) and then “Activates” the first one. The Items collection and Activation capabilities come from the Conductor base class. Just to remind you, I’m going to cover Screens and Conductors much more thoroughly in a future article. Also, take note of the [SurviveTombstone] attribute. We’ll get to that soon. First, here’s the view that this is bound to:


<phone:PhoneApplicationPage x:Class="Caliburn.Micro.HelloWP7.PageTwo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<StackPanel Grid.Row="0"
Margin="24,24,0,12">
<TextBlock Text="WP7 Caliburn.Micro"
Style='{StaticResource PhoneTextNormalStyle}' />
<TextBlock Text='Page Two'
Margin='-3,-8,0,0'
Style='{StaticResource PhoneTextTitle1Style}' />
</StackPanel>

<Grid Grid.Row='1'>
<Grid.RowDefinitions>
<RowDefinition Height='Auto' />
<RowDefinition Height='*' />
</Grid.RowDefinitions>

<ListBox x:Name='Items'>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text='{Binding DisplayName}'
Margin='2 0 12 0'
FontSize='30' />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation='Horizontal' />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

<ContentControl x:Name='ActiveItem'
HorizontalContentAlignment='Stretch'
VerticalContentAlignment='Stretch'
Grid.Row='1' />
</Grid>
</Grid>
</phone:PhoneApplicationPage>

It looks like this when running:


PageTwo


This view is a bit more complex, but you only need concern yourself with the ListBox and the ContentControl. Here, we are using these two controls to create a Tabbed UI. The ListBox plays the part of the TabHeaders. It’s name causes it to automatically have its ItemsSource bound to the Items collection on the VM and its SelectedItem bound to the ActiveItem on the VM (these properties come from Conductor base class). The ContentControl has its Content property automatically bound to the ActiveItem property on the View and it is done using the View.Model attached property I discussed in the previous article. This allows the ActiveItem to be conventionally wired up to it’s view, enabling the display of the “Tab Content”. And yes, I am going to cover conventions in more depth in a future article as well. But, I want you to get a taste of how conventions, composition and conductors all play together. What we’ve just created is an MDI interface inside this particular page completely driven by the ViewModel. Let’s take a look at that TabViewModel and it’s corresponding View. First the VM:


using System;
using System.Windows;
using Microsoft.Phone.Tasks;

[SurviveTombstone]
public class TabViewModel : Screen, ILaunchChooser<PhoneNumberResult>
{
string text;

[SurviveTombstone]
public string Text
{
get { return text; }
set
{
text = value;
NotifyOfPropertyChange(() => Text);
}
}

public void Choose()
{
TaskLaunchRequested(this, TaskLaunchEventArgs.For<PhoneNumberChooserTask>());
}

public event EventHandler<TaskLaunchEventArgs> TaskLaunchRequested = delegate { };

public void Handle(PhoneNumberResult message)
{
MessageBox.Show("The result was " + message.TaskResult, DisplayName, MessageBoxButton.OK); //You should abstract this…
}
}

Now you should be noticing some interesting tidbits here. I’ll be coming back to those in a minute. Let’s take a look at the last piece in our application’s UI, the view for these tabs:


<UserControl x:Class="Caliburn.Micro.HelloWP7.TabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="{StaticResource PhoneChromeBrush}">
<TextBlock x:Name="DisplayName"
Margin="8 0 0 0"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}" />
<TextBox x:Name="Text" />
<Button Content="Choose"
x:Name="Choose" />
</StackPanel>
</UserControl>

Here we just have a TextBox bound to our Text property and a Button that will execute our Choose method. Hopefully, you can see how all that comes together in the image above. Let’s add one more thing, just to make our application complete before we dive into the really interesting parts. I mentioned that I had modified my SimpleContainer to create a custom PhoneContainer. All I did was plug in a special Caliburn.Micro piece that helps us use Launchers/Choosers easier (discussed shortly). Pretty much every IoC Container has a place to plug in custom “activation” logic. This is code that gets a chance to execute whenever the container creates an instance of a class. For my simple container, I provided an overridable method to plug this in. It’s a bit different for each container, but it’s a powerful extensibility point. By plugging in CMs InstanceActivator class, we will make launchers/chooser so much easier for you. For now, I’ll show you what the PhoneContainer looks like. We’ll get to the launcher/chooser bit a little later:


using System;

public class PhoneContainer : SimpleContainer
{
public PhoneContainer()
{
Activator = new InstanceActivator(type => GetInstance(type, null));
}

public InstanceActivator Activator { get; private set; }

protected override object ActivateInstance(Type type, object[] args)
{
return Activator.ActivateInstance(base.ActivateInstance(type, args));
}
}

 


Tombstoning


Now that we have all the pieces, I can explain why I’ve gone through the trouble of setting all this up: Tombstoning. At any point in time a WP7 application has to expect that it will be shutdown by the OS. For example, if someone is using your application and their friend calls them, the phone will Tombstone your application in order to process the call. When the call is over, your application will be Resurrected. A well designed WP7 application should restore itself to the exact state it was in before Tombstoning. The phone’s OS remembers the page you were on and Navigates to it automatically (read more here). Our Navigation system described above ensures that it gets hooked up with the right ViewModel. But, you must ensure that that View/ViewModel is put back in the same state it was in before Tombstoning. That’s where the [SurviveTombstone] attribute you saw comes into play. Whenever the OS attempts to Tombstone your application, Caliburn.Micro will grab the current page, extract its DataContext and see if it has any attributes that implement ITombstone. This interface is used to serialize a class or property by flattening it and storing it into the PhoneApplicationService.State property, which is persisted by the OS solely for the purpose of Resurrection (if it occurs). The [SurviveTombstone] attribute is a simple out-of-the-box implementation of this interface that understands how to walk an object graph, examine its properties and persist them. It has special knowledge of Conductors as well, so that it will persist their ActiveItem correctly and inspect their children. This is an opt-in mechanism. You must decorate every class as well as the properties you want persisted. If you look at the classes above, you can see that the PageTwoViewModel is attributed. Because it is a Conductor, the index of its ActiveItem will be persisted and each of its Items will be traversed as well. Because each TabViewModel is attributed, it will be inspected for persistable properties. The Text property is attributed, so that property on each child item will be persisted. This mechanism is customizable and entirely replaceable if you don’t like it. First, you can create your own attributes that implement ITombstone to customize all or part of the process. Second, you can override the SelectInstancesToTombstone and SelectInstancesToResurrect methods on the PhoneBootstrapper to determine what should be persisted to begin with. As I mentioned, by default, we only inspect the DataContext of the current page. But, you could grab several key VMs from your IoC and supply them to the persistence mechanism here if you like. Lastly, you can override the Tombstone and Resurrect methods on the PhoneBootstrapper to replace the built-in mechanism all together. If you download the the sample attached to this article and run the application, you will see that this all works as expected. Try navigating to the second page, selecting a tab other than the first one and typing some text into the text box. Next, click the “Choose” button (we are going to talk about choosers next). After the chooser launches, press the phone’s back button to cancel. Immediately press F5 in Visual Studio to re-attach the debugger (remember that that chooser caused your application to be tombstoned). After the debugger is attached, your application goes back to page two with the proper tab selected and the text filled back in the text box. The chooser result is displayed as well.** Here’s what you should see:


PageTwoPostChooser


 


Launchers and Choosers


One unique aspect to WP7 development is Tasks. They come in two flavors. Tasks that simply launch a built-in phone application without returning data, such as EmailComposeTask, are called Launchers. Tasks that return data back to your application, such as PhoneNumberChooserTask, are called Choosers. Now, let me tell you how I really feel…the WP7 API for Choosers is a software design abomination. You need to know how it works for your own benefit and to better appreciate what I am going to show you, so let me take a moment to explain. Executing a task is as simple as creating the class and calling its Show method. But, remember that Tombstoning thing? As soon as you call Show, your application gets Tombstoned. So, right now you should be wondering, “But what if I am using a Chooser? How do I get the results back into my application?” Well, the official guidance is that you should have created that Chooser in the constructor of your code-behind file and wired up its completed event. So, when the phone infrastructure tries to resurrect your application, it will navigate to that page, the chooser will be re-created and the event re-wired.  When you re-wire to the event, your event handler is called immediately. The infrastructure is trying to fake a cross-app-instance callback. Now, does that sound like it’s going to play nice with MVVM…or any attempt at decent software design? One thing is for sure, you have to be very careful about when you create the Chooser and wire the event. For example, lets say you had the idea that you would create these Choosers as singletons at startup and just wire their events then and there, in order to remove that from your pages. Well, it won’t work. You wired the event too early. It’s also quite possible to wire it too late. It must be done at just the right time. But, what is the right time? From what I can tell, it’s not clearly defined by their API. If you do it in your page’s constructor, it should work though. But should you handle the event in the constructor? Probably not, especially since your main UI isn’t even visible yet. So, you probably at least need to wire for the Loaded event and delay handling of the callback until the UI is visible. As you can see, this part of the WP7 API is a disaster. I’ve done some things to try to improve this and make it more friendly to UI architecture. The following functionality is handled by the InstanceActivator and must be hooked into your IoC container for it to be enabled. Here’s how it works:


  • First, developers register the Launcher/Chooser types they intend to use with the Activator. If you look back at the sample’s bootstrapper, you will see that I used the methods InstallLauncher and InstallChooser.
  • Each instance that is created by the IoC container will be inspected by the Activator to see if it implements certain interfaces.
  • If the instance implements ILaunchTask or ILaunchChooser<TResult>, the activator will wire itself to the event defined by the interface.
  • When the VM wants to execute a task, it raises ILaunchTask.TaskLaunchRequested. You can see an example of this in the the TabViewModel.Choose method.
  • The infrastructure is notified of the event and then determines if the sender implements IConfigureTask<TTask>. If it does, the task instance is passed to the sender’s Configure method. (Some tasks have parameters which must be set, but the sample above does not.)
  • Next, the infrastructure “records” the sender of the event so that it knows who to call back after resurrection.
  • The infrastructure now calls Show on the task and your application is Tombstoned.
  • When, your application resurrects, it should put itself back in the state it was before tombstoning.
  • Since all instances come from the IoC container, we inspect each instance that is created to see if it was the one we “recorded” as the sender of the task launch.
  • When we find a match, we attempt to call ILaunchChooser<TResult>.Handle with the Chooser result at the “latest possible time.” The latest possible time is evaluated based on the features of the class. If it is IViewAware, we call handle after the View’s Loaded event fires. If it isn’t but implements IActivate, we call Handle after the class is activated (assuming it isn’t already activated.) If these conditions aren’t met, we call Handle immediately.

It sounds complicated. That’s mostly because, frankly, Choosers are not very friendly to any sort of reasonable software design. However, I think the result of the custom Activator, especially when combined with the [SurviveTombstone] attribute is a very natural developer experience. If you run the sample, you will see that this does indeed work and that the Chooser result is passed back to the correct VM after it’s View is shown.


 


I’ve gone through a lot of WP7 specific stuff in this article. Please remember that all of this is completely optional. You can still leverage Caliburn.Micro without it. I think the FrameAdapter will prove to be the most useful and generalizable feature for building UI. Hopefully the simple tombstoning mechanism and Launcher/Chooser abstraction will help you too.


 


*Even though the IGuardClose interface was designed to handle async scenarios, you must use it synchronously in WP7. This is due to a flaw in the design of Silverlight Navigation Framework.


 


 


**Sometimes the first time I do this, the debugger does not re-attach correctly and the application never resurrects at all. If this happens to you, just try it again ;)

Saturday, July 17, 2010  |  From .NET & Funky Fresh

We briefly introduced actions in Pt. 1, but there is so much more to know. To begin our investigation, we’ll take our simple “Hello” example and see what it looks like when we explicitly create the actions rather than use conventions. Here’s the Xaml:


 


<UserControl x:Class="Caliburn.Micro.Hello.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org">
<StackPanel>
<TextBox x:Name="Name" />
<Button Content="Click Me">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SayHello" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</UserControl>

 


As you can see, the Actions feature leverages System.Windows.Interactivity for it’s trigger mechanism. This means that you can use anything that inherits from System.Windows.Interactivity.TriggerBase to trigger the sending of an ActionMessage.*  Perhaps the most common trigger is an EventTrigger, but you can create almost any kind of trigger imaginable or leverage some common triggers already created by the community.  ActionMessage is, of coarse, the Caliburn.Micro-specific part of this markup. It indicates that when the trigger occurs, we should send a message of “SayHello.”  So, why do I use the language “send a message” instead of “execute a method” when describing this functionality? That’s the interesting and powerful part.  ActionMessage bubbles through the Visual Tree searching for a target instance that can handle it. If a target is found, but does not have a “SayHello” method, the framework will continue to bubble until it finds one, throwing an exception if no “handler” is found.** This bubbling nature of ActionMessage comes in handy in a number of interesting scenarios, Master/Details being a key use case. Another important feature to note is Action guards. When a handler is found for the “SayHello” message, it will check to see if that class also has either a property or a method named “CanSayHello.” If you have a guard property and your class implements INotifyPropertyChanged, then the framework will observe changes in that property and re-evaluate the guard accordingly. We’ll discuss method guards in further detail below.


Now you’re probably wondering how to specify the target of an ActionMessage. Looking at the markup above, there’s no visible indication of what that target will be. So, where does that come from? Since we used a Model-First approach, when Caliburn.Micro (hereafter CM) created the view and bound it to the ViewModel using the ViewModelBinder, it set this up for us. Anything that goes through the ViewModelBinder will have its action target set automatically. But, you can set it yourself as well, using the attached property Action.Target. Setting this property positions an ActionMessage “handler” in the Visual Tree attached to the node on with you declare the property. It also sets the DataContext to the same value, since you often want these two things to be the same. However, you can vary the Action.Target from the DataContext if you like. Simply use the Action.TargetWithoutContext attached property instead. One nice thing about Action.Target is that you can set it to a System.String and CM will use that string to resolve an instance from the IoC container using the provided value as its key. This gives you a nice way of doing View-First MVVM if you so desire. If you want Action.Target set and you want Action/Binding Conventions applied as well, you can use the Bind.Model attached property in the same way.


Let’s see how we would apply this to achieve MVVM using a View-First technique (gasp!) Here’s how we would change our bootstrapper:


 


public class MefBootstrapper : Bootstrapper
{
//same as before

protected override void DisplayRootView()
{
Application.Current.RootVisual = new ShellView();
}

//same as before
}

 


Because we are using View-First, we’ve inherited from the non-generic Bootstrapper. The MEF configuration is the same as seen previously, so I have left that out for brevity’s sake. The only other thing that is changed is how the view gets created. In this scenario, we simply override DisplayRootView, instantiate the view ourselves and set it as the RootVisual (or call Show in the case of WPF). Next, we’ll slightly alter how we are exporting our ShellViewModel, by adding an explicitly named contract:


 


[Export("Shell", typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
//same as before
}

 


Finally, we will alter our view to pull in the VM and perform all bindings:


 


<UserControl x:Class="Caliburn.Micro.ViewFirst.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
cal:Bind.Model="Shell">
<StackPanel>
<TextBox x:Name="Name" />
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
</UserControl>

 


Notice the use of the Bind.Model attached property. This resolves our VM by key from the IoC container, sets the Action.Target and DataContext and applies all conventions. I thought it would be nice to show how View-First development is fully supported with CM, but mainly I want to make clear the various ways that you can set targets for actions and the implications of using each technique. Here’s a summary of the available attached properties:


  • Action.Target – Sets both the Action.Target property and the DataContext property to the specified instance. String values are used to resolve an instance from the IoC container.
  • Action.TargetWithoutContext – Sets only the Action.Target property to the specified instance. String values are used to resolve an instance from the IoC container.
  • Bind.Model – View-First - Set’s the Action.Target and DataContext properties to the specified instance. Applies conventions to the view. String values are used to resolve an instance from the IoC container.
  • View.Model – ViewModel-First – Locates the view for the specified VM instance and injects it at the content site. Sets the VM to the Action.Target and the DataContext. Applies conventions to the view.

 


Now, let’s take a look at another interesting aspect of ActionMessage: Parameters. To see this in action, let’s switch back to our original ViewModel-First bootstrapper, etc. and begin by changing our ShellViewModel to look like this:


 


using System.ComponentModel.Composition;
using System.Windows;

[Export(typeof(IShell))]
public class ShellViewModel : IShell
{
public bool CanSayHello(string name)
{
return !string.IsNullOrWhiteSpace(name);
}

public void SayHello(string name)
{
MessageBox.Show(string.Format("Hello {0}!", name));
}
}

 


There are a few things to note here. First, we are now working with a completely POCO class; no INPC goop here. Second, we have added an input parameter to our SayHello method. Finally, we changed our CanSayHello property into a method with the same inputs as the action, but with a bool return type. Now, let’s have a look at the Xaml:


 


<UserControl x:Class="Caliburn.Micro.HelloParameters.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org">
<StackPanel>
<TextBox x:Name="Name" />
<Button Content="Click Me">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SayHello">
<cal:Parameter Value="{Binding ElementName=Name, Path=Text}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</UserControl>

 


Our markup now has one modification: We declared the parameter as part of the ActionMessage using an ElementName Binding. You can have any number of parameters you desire. Value is a DependencyProperty, so all the standard binding capabilities apply to parameters. Did I mention you can do all this in Blend?


 


ActionsInBlend


 


One thing that is nice about this is that every time the value of a parameter changes, we’ll call the guard method associated with the action(CanSayHello in this case) and use its result to update the UI that the ActionMessage is attached to. Go ahead and run the application. You’ll see that it behaves the same as in previous examples.


In addition to literal values and Binding Expressions, there are a number of helpful “special” values that you can use with parameters. These allow you a convenient way to access common contextual information:


  • $eventArgs – Passes the Trigger’s EventArgs or input parameter to your Action. Note: This will be null for guard methods since the trigger hasn’t actually occurred.
  • $dataContext – Passes the DataContext of the element that the ActionMessage is attached to. This is very useful in Master/Detail scenarios where the ActionMessage may bubble to a parent VM but needs to carry with it the child instance to be acted upon.
  • $source – The actual FrameworkElement that triggered the ActionMessage to be sent.

You must start the variable with a “$” but the name is treated in a case-insensitive way by CM.


 


Word to the Wise


Parameters are a convenience feature. They are very powerful and can help you out of some tricky spots, but they can be easily abused. Personally, I only use parameters in the simplest scenarios. One place where they have worked nicely for me is in login forms. Another scenario, as mentioned previously is Master/Detail operations.


 


Now, do you want to see something truly wicked? Change your Xaml back to this:


 


<UserControl x:Class="Caliburn.Micro.HelloParameters.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox x:Name="Name" />
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
</UserControl>

 


Running the application will confirm for you that CM’s conventions even understand ActionMessage parameters. We’ll discuss conventions a lot more in the future, but you should be happy to know that these conventions are case-insensitive and can even detect the before-mentioned “special” values.


 


Now, lets look at a simple Master/Detail scenario that demonstrates ActionMessage bubbling, but let’s do it with a shorthand syntax that is designed to be more developer friendly. We’ll start by adding a simple new class named Model:


 


using System;

public class Model
{
public Guid Id { get; set; }
}

 


And then we’ll change our ShellViewModel to this:


 


using System;
using System.ComponentModel.Composition;

[Export(typeof(IShell))]
public class ShellViewModel : IShell
{
public BindableCollection<Model> Items { get; private set; }

public ShellViewModel()
{
Items = new BindableCollection<Model>{
new Model { Id = Guid.NewGuid() },
new Model { Id = Guid.NewGuid() },
new Model { Id = Guid.NewGuid() },
new Model { Id = Guid.NewGuid() }
};
}

public void Add()
{
Items.Add(new Model { Id = Guid.NewGuid() });
}

public void Remove(Model child)
{
Items.Remove(child);
}
}

 


Now our shell has a collection of Model instances along with the ability to add or remove from the collection. Notice that the Remove method takes a single parameter of type Model. Now, let’s update the ShellView:


 


<UserControl x:Class="Caliburn.Micro.BubblingAction.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<StackPanel>
<ItemsControl x:Name="Items">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="Remove"
cal:Message.Attach="Remove($dataContext)" />
<TextBlock Text="{Binding Id}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Add"
cal:Message.Attach="Add" />
</StackPanel>
</UserControl>

 


The first thing to notice is that we are using a more Xaml-developer-friendly mechanism for declaring our ActionMessages. The Message.Attach property is backed by a simple parser which takes its textual input and transforms it into the full Interaction.Trigger/ActionMessage that you’ve seen previously. If you work primarily in the Xaml editor and not in the designer, you’re going to like Message.Attach. Notice that neither Message.Attach declarations specify which event should send the message. If you leave off the event, the parser will use the ConventionManager to determine the default event to use for the trigger. In the case of Button, it’s Click. You can always be explicit of coarse. Here’s what the full syntax for our Remove message would look like if we were declaring everything:


 


<Button Content="Remove"
cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]" />

 


Suppose we were to re-write our parameterized SayHello action with the Message.Attach syntax. It would look like this:


 


<Button Content="Click Me"
cal:Message.Attach="[Event Click] = [Action SayHello(Name.Text)]" />

 


But we could also leverage some smart defaults of the parser and do it like this:


 


<Button Content="Click Me"
cal:Message.Attach="SayHello(Name)" />

 


You can specify literals as parameters as well and even declare multiple actions by separating them with a semicolon:


 


<Button Content="Let's Talk"
cal:Message.Attach="[Event MouseEnter] = [Action Talk('Hello', Name.Text)];
[Event MouseLeave] = [Action Talk('Goodbye', Name.Text)]" />

 


WARNING: Those developers who ask me to expand this functionality into a full-blown expression parser will be taken out back and…dealt with. Message.Attach is not about cramming code into Xaml. It’s purpose is to provide a streamlined syntax for declaring when/what messages to send to the ViewModel. Please don’t abuse this.


 


If you haven’t already, run the application. Any doubts you had will hopefully be put to rest when you see that the message bubbling works as advertised :) Something else I would like to point out is that CM automatically performs type-conversion on parameters. So, for example, you can pump TextBox.Text into a System.Double parameter without any fear of a casting issue.


So, we’ve discussed using Interaction.Triggers with ActionMessage, including the use of Parameters with literals, element bindings*** and special values. We’ve discussed the various ways to set the action target depending on your needs/architectural style: Action.Target, Action.TargetWithoutContext, Bind.Model or View.Model. We also saw an example of the bubbling nature of ActionMessage and demoed it using the streamlined Message.Attach syntax. All along the way we’ve looked at various examples of conventions in action too. Now, there’s one final killer feature of ActionMessage we haven’t discussed yet…Coroutines. But, that will have to wait until next time.


 


*Currently, the full version of Caliburn is not based on System.Windows.Interactivity. Caliburn’s trigger mechanism was around long before Blend’s.  You may notice a shocking similarity in the markup. That said, Caliburn v2.0 will be migrated to use the Blend model in the near future.


**Actually, if no handler is found, before an exception is thrown, the framework will check the current DataContext to see if it has the requested method. This seamed like a reasonable fallback behavior.


***One important detail about ElementName Bindings that I didn’t mention…It doesn’t work with WP7 currently. Due to the fact that WP7 is based on a version of Silverlight 3 which had an incomplete implementation of DependencyObject/DependencyProperty, the infrastructure is not present to make this work in any sort of sane way. However, parameter literals and special values still work as described along with all the rest of the ActionMessage features.

 .NET & Funky Fresh News Feed 
Last edited Aug 21 at 6:48 PM by EisenbergEffect, version 20

 

Want to leave feedback?
Please use Discussions or Reviews instead.

Archived page comments (1)

Updating...
© 2006-2010 Microsoft | Get Help | Privacy Statement | Terms of Use | Code of Conduct | Advertise With Us | Version 2010.8.10.17093