-
First steps with Caliburn Micro in Windows Phone 8 – Tombstoning
Tombstoning is the joy and the pain of every Windows Phone developer: it’s a joy because it’s a really smart mechanism to manage the suspension process of an application and to “simulate” that an application has never been closed. But it’s also a pain, because managing it correctly it’s not easy, and this is even more true for a MVVM application. The main reason is that usually tombstoning is managed using the navigation events of a page: when the user navigates away from a page (OnNavigatedFrom) we save the status of the page; when the user navigates to the page (OnNavigatedTo) we retrieve the previous status. in MVVM we don’t have direct access to the navigation events, since they are available only in the view: for this reason, every MVVM toolkit usually provides a way to hook up to these events also in the view model, to properly save and restore the state.
Caliburn Micro uses another approach: we create another class, that is connected to the ViewModel, and we specify what to do when the application is suspended.
Let’s start with a real example: create a new Windows Phone project and add Caliburn Micro using NuGet. As explained in the other post, create a new ViewModel for the first page and connect them using the standard naming convention.
Now we’re going to add a TextBox control inside the page and, using the standard naming convention, we bind it to a string property in our ViewModel so that, everytime the user writes something in the TextBox, the value is saved in the property.
<TextBox x:Name="Name" />
public class MainPageViewModel: PropertyChangedBase { private string name; public string Name { get { return name; } set { name = value; NotifyOfPropertyChange(() => Name); } } }
Let’s do an experiment first to test the tombstoning process. Let’s start the application: write something in the TextBox, suspend the application by pressing the Start button and then, by pressing the Back button, go back to the application. The text will still be there: this happens because, as a standard behavior, the application is suspended, but the process is kept in memory, so there’s no need to restore the state.
Now we need to simulate the tombstoning: Visual Studio provides a special option in the project’s properties to test it, since there’s no manual way to trigger it. The operatying system always suspends an application, as a standard behavior: only when the system is getting low on resources it can choose to tombstone an app. You can find this option by right clicking on the project in Visual Studio: choose Properties and, in the Debug tab, you’ll find a checkbox, with the label “Tomstone upon activation while debugging”. Enable it and now repeat the previous test: you’ll notice that, this time, when the application is activated the text in the TextBox will be gone.
Here comes tombstoning: we need to save the value in TextBox and restore it when the application is activated. Caliburn Micro provides an easy way to do it: you’ll have to create another class, that will manage the tombstoning for you.
This class will have to inherit from the **StorageHandler
,** where T is the ViewModel of the view which state we need to save. Here is an example: public class MainPageModelStorage: StorageHandler<MainPageViewModel> { public override void Configure() { Property(x => x.Name) .InPhoneState(); } }
When you implement the **StorageHandler
** class you are required to implement the **Configure** method, that contains the “instructions” for Caliburn Micro about what to do when the app is suspended. We use the **Property** object and, using a lambda expression, we specify which property of the View Model we want to save during the suspension. The Intellisense will help you: since x, in the lambda expression, is your ViewModel (in the sample, **MainPageViewModel**), you’ll have access to all the public properties you have defined (in our sample, the **Name** property). In the end you can specify where the status should be saved: with the method **InPhoneState()** the property is saved in the transient Windows Phone state, that is erased in case the application is closed or opened from the beginning. It’s the perfect solution for our scenario: imagine that our TextBox is part of a form, that the user needs to fill. It’s important to keep the status if the app is suspended, but it’s correct to start over from scratch in case the application is restarted. In case, instead, we want to restore the value of our property every time the app is restored, we can use the InAppSettings() method:
public class MainPageModelStorage: StorageHandler<MainPageViewModel> { public override void Configure() { Property(x => x.Name) .InAppSettings(); } }
Let’s try it: open the application, write something in the TextBox and suspend it. If you press Back, the app will be reopened and the text will still be there, even if we’ve told to the the project to tombstone the app: Caliburn Micro has automatically saved and restored the value of the Name property of our ViewModel and the final result, for the user, is that it’s like the app has been regularly suspended. If we close the app using the Back button instead of suspending it and we open it again, this time the text will be gone: it’s correct, because we’ve saved the status in the phone state. If we change the Configure method of the MainPageModelStorage class to save the data in the application settings, instead, we will notice that the text in the TextBox is restored even after the app has been closed.
###
###
It’s not over yet
We haven’t finished yet to dig about Caliburn Micro: we still have to see how to manage messaging. Stay tuned, meanwhile you can play with the sample project below.
The Caliburn Micro posts series
in
-
First steps with Caliburn Micro in Windows Phone 8 – Collections and navigation
We continue our journey about Caliburn Micro and how to use this MVVM framework in a Windows Phone 8 application by understanding how to manage collections and navigation.
###
Collections
One of the most common scenarios in a Windows Phone application is the usage of collections: we have a list of data and we need to display it in a ListBox or in LongListSelector. The standard approach is to create a collection in the code (usually, when we’re talking about the XAML world, we use an ObservableCollection) and then to bind it to the ItemsSource property. Guess what? Caliburn Micro has another naming convention for that! And a pretty smart one too! To assign the collection to the ItemsSource property we use the standard naming convention we already know: the name of the property in the view model should match the name of the control. But here comes the smart decision: if you create a property which name is Selected followed by the name of the control in singular, it will be automatically bound with the SelectedItem property of the control. Let’s make an example:
<ListBox x:Name="Items"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding}" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
In the XAML we add a ListBox with a simple template: it will simply display, for every item in the collection, a TextBlock with the value of the single item. The name of the ListBox is Items so, by following the Caliburn Micro naming convention, we expect to have in the view model a property called Items, which is the collection that will be displayed.
private ObservableCollection<string> items; public ObservableCollection<string> Items { get { return items; } set { items = value; NotifyOfPropertyChange(() => Items); } }
And here’s come the magic:
private string selectedItem; public string SelectedItem { get { return selectedItem; } set { selectedItem = value; NotifyOfPropertyChange(() => SelectedItem); MessageBox.Show(value); } }
As you can see the name of the property is SelectedItem, which is the name of the other property in singular (Items –> Item) prefixed by the word Selected. In the setter of the property we’ve added a line of code to display, using a MessageBox, the value of the selected property, that will be helpful for our tests. Now let’s try it: in the public constructor of the view model let’s add some fake data and assign it to the Items property.
public MainPageViewModel() { Items = new BindableCollection<string> { "Matteo", "Mario", "John" }; }
If you launch the application and you’ve correctly followed the steps the ListBox will contain the three test values we’ve defined: by tapping on one of the elements a MessageBox with the selected name will appear.
###
Navigation
Usually managing the navigation from a page to another of the application is one of the trickiest tasks using MVVM. The biggest problem to face is that in Windows Phone we use the NavigationService, that can be used only in the code behind that is connected to a view. You can’t directly access to it from another class, for example, like a ViewModel. To support the developer Caliburn Micro comes with a built in NavigationService, that can be used in a ViewModel by simply adding a reference in the public constructor of the application. The built in dependency injection container will take care of resolving the dependency for you and will give you access to it. So, the first thing to use manage navigation in a MVVM application developed with Caliburn Micro is to change the public constructor of your view model, like in the following example:
public class MainPageViewModel : PropertyChangedBase { private readonly INavigationService navigationService; public MainPageViewModel(INavigationService navigationService) { this.navigationService = navigationService; } }
From now on, you’ll be able to use the NavigationService inside your view model: you won’t have to register anything in the bootstrapper, since Caliburn Micro will take care of everything (as for every other service that is embedded with the toolkit).
The NavigationService that comes with the toolkit supports a view model first approach: instead of declaring which is the URL of the page where we want to take the user (that is the standard approach), we declare which is the ViewModel we want to display. The service will take care of creating the correct URL and display the view that is associated with the view model. Let’s see how does it work.
First we need a new page where to redirect the user: add to your project a new page and a new class in the ViewModels folder. Remember to use the naming convention we’ve learned in the second post of the series: if the name of the page is Page2View.xaml, the name of the ViewModel will have to be Page2ViewModel.cs. Before moving on, you have to remember to register the new view model in the Configure method of the bootstrapper, like in the following example:
protected override void Configure() { container = new PhoneContainer(RootFrame); container.RegisterPhoneServices(); container.PerRequest<MainPageViewModel>(); container.PerRequest<Page2ViewModel>(); AddCustomConventions(); }
Now add a button in the main page of your application and, using the naming convention we’ve learned in the previous post, assign to it a method in your view model, that will trigger the navigation towards the second page.
<Button Content="Go to page 2" x:Name="GoToPage2" />
public void GoToPage2() { navigationService.UriFor<Page2ViewModel>() .Navigate(); }
With the **UriFor
** method of the navigation service we get the needed URL for our view model, then we call the **Navigate**()method to trigger the navigation and redirect the user to the requested page. Navigation with parameters
You should already know that, when navigating from a page to another, you are able to carry some parameters in the query string, that can be used in the new page, like in the following sample
/Page2View.xaml?Name=Matteo
Using the NavigationContext you are able, in the view Page2View.xaml, to retrieve the value of the Name property that is passed using a query string. How to do it using Caliburn Micro? The first thing is to define, in our destination page’s view model (in our example, the class Page2ViewModel) a property, that will hold the value of the parameter.
public class Page2ViewModel: PropertyChangedBase { private string name; public string Name { get { return name; } set { name = value; NotifyOfPropertyChange(() => Name); } }
Then, we change the navigation operation like this:
public void GoToPage2() { navigationService.UriFor<Page2ViewModel>() .WithParam(x => x.Name, "Matteo") .Navigate(); }
We’ve added the method WithParam, that accepts two parameters: the first one is the property of the destination view model that will hold our value and it’s specified using the lambda syntax (x represents the destination view model, in our example the instance of the Page2ViewModel class); the second parameter is the value that the property will have. When the Page2View.xaml view will be loaded, the Page2ViewModel will hold, in the Name property, the value of the parameter we’ve passed during the navigation, so we can use it for our purposes. For example, we can simply display it by adding a in the XAML a TextBlock with the same name of the property (do you remember the naming convention?)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <TextBlock x:Name="Name"></TextBlock> </StackPanel> </Grid>
Important! It’s true that Caliburn Micro does a lot of magic, but the navigation with parameter feature is still based on query string parameter. The only magic is that these parameters are automatically injected in the properties of your view model, but they still are strings: you can use the WithParam method to pass to the new view just plain values, like strings and number. You can’t use it to pass complex objects.
To be continued
The journey is not ended yet, we still have to see how to manage messages and tombstoning with Caliburn Micro. Coming soon in the next posts! While you wait, you can download the sample project and start playing with it!
The Caliburn Micro posts series
in
-
First steps with Caliburn Micro in Windows Phone 8 – Actions
In the previous post we’ve seen how to setup a Windows Phone application to use Caliburn Micro as a MVVM Framework. We’ve seen also the first conventions used by the toolkit, to connect together a View with its ViewModel and to bind a property to a control’s property. In this post we’ll see how to connect a control to an action, so that when the user interacts with the control the action is executed.
Commands in Caliburn Micro
Usually to accomplish this task using MVVM Light or the standard XAML approach we use the Command property: we would define an object that implements the ICommand interface and define the operation that should be executed when it’s invoked. In the end, the object is connected with the Command property of a Button, for example, using binding. This approach is very repetitive, because we need to create an ICommand object for every operation while, in the end, what we really need is to define just the method that should be invoked. Caliburn Micro avoid this requirement by using, guess what, a naming convention, similar to the one we’ve seen to bind properties to a control. Basically, you just need to declare in your view model a method which name matches the name of the control.
For example, declare a Button like this:
<Button Content="Show name" x:Name="ShowNameAction" />
Then, in your code, you’ll have a method like the following one:
public void ShowNameAction() { MessageBox.Show("Clicked"); }
Now if you launch the application and you press on the button you’ll see the message on the screen. The magical naming convention did the trick again! And what if we need a property to set the content of the button and, at the same time, an action to be triggered when the button is clicked? In this case we have a conflict with the naming convention rule: we can’t have in the view model both a method and a property with the same name.
In this case, we need to use the long syntax, that uses the behaviors available in the System.Windows.Interactivity namespace. For this reason, we need to add to our XAML the following namespaces:
_xmlns:i=”clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity”
xmlns:cal=”clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro”
_Now you need to change the Button declaration like in the following sample:
<Button x:Name="ShowName"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="ShowNameAction" /> </i:EventTrigger> </i:Interaction.Triggers> </Button>
As a label for the button will be used a property called ShowName declared in the ViewModel; instead, the ShowNameAction method will be executed when the button is clicked. One advantage of using this syntax is that you are able to attach a method also to other events: by default, using the standard naming convention, a method is hooked with the default event of the control (in case of a Button, it’s the Click event). With this syntax, instead, it’s enough to change the EventName property of the EventTrigger with another one (for example, DoubleTap) to connect the method with that event.
Caliburn Micro provides also a short syntax to do the same:
<Button cal:Message.Attach="[Event Click] = [Action ShowName]" />
The syntax is very simple: by using the Message.Attach attached property we define first the event we want to hook (with the keyword Event followed by the name of the event), then the name of the method that should be executed (with the keyword Action followed by the name of the method). The pros of the long syntax is that is supported by Blend, but it’s more verbose; the short syntax is easier to remember and to use, but Blend doesn’t like it. It’s up to you which syntax to use: personally I don’t use Blend too much, so losing the ability to see and interact with the button in Blend is not a big deal for me.
Controlling the action
One of the most interesting features that is available in the command pattern is the CanExecute concept: every command can be controlled by the developer, so that he can enable or disable it according to a specific condition. The coolest thing is that the control that is bound with the command will automatically change his status according to this condition: if the command is disabled, for example, the button will be grayed and the user won’t be able to click on it.
Basically, the CanExecute action returns a boolean value, that determines if the command can be executed or not. Every time something changes, this action should be evaluated again. A classic example is a form, that shouldn’t be submitted until the user has filled all the required fields. By default, the submit button is disabled but, every time a field is filled by the user, the action should be evaluated again, because the status of the button can change.
Also in this case Caliburn Micro uses conventions to support this feature: you just need to create in your ViewModel a boolean property, with the same name of the method prefixed by the Can word. Here is how to extend the previous example, by adding a Checkbox in our page, which we’re going to bound to a boolean property. The button should be activated only when the checkbox is enabled.
Here is the XAML in the view:
<StackPanel> <Button x:Name="ShowName" Content="Click me" /> <CheckBox x:Name="IsEnabled" Content="IsEnabled" /> </StackPanel>
And here is the code in our ViewModel:
public class MainPageViewModel: PropertyChangedBase { private bool isEnabled; public bool IsEnabled { get { return isEnabled; } set { isEnabled = value; NotifyOfPropertyChange(() => IsEnabled); NotifyOfPropertyChange(() => CanShowName); } } public bool CanShowName { get { return IsEnabled; } } public void ShowName() { MessageBox.Show("Clicked"); } }
As you can see, other than defining the ShowName method (that is invoked when the ShowName button is clicked), we create a boolean property which name is CanShowName. In the end, we create a property called IsEnabled, that is connected to the checkbox in the view. This way, every time the checkbox is enabled, the IsEnabled property is set to true and the same happens for the CanShowName property. The only thing to highlight is that, every time we change the value of the IsEnabled property, we call the NotifyOfPropertyChange method not only on the property itself, but also on the CanShowName property. This way, every time the IsEnabled property changes, also the CanShowName property is evaluated again and the button’s status is changed according to the new value.
To be continued
In the next posts we’ll keep digging in using Caliburn Micro, to manage collections, tombstoning, messaging and navigation. For the moment, you can start playing with the sample project below to take a deeper look to what we’ve learned in this post.
**
The Caliburn Micro posts series
in
subscribe via RSS