24 July 2012

A WinRT behavior to mimic EventToCommand

This is deprecated. Please use the official behaviors SDK now. See here for a simple migration guide

Updated September 2 2012 with two sample applications

Whoever used the MVVMLight framework by Laurent Bugnion is familiar with EventToCommand, especially those who used it on Windows Phone before the advent of 7.5 (or SDK version 7.1.1). This utility enables triggers to fire commands on the viewmodel

Unfortunately, in WinRT there is no such thing as a trigger, so this method cannot be used, and MVVMLight for WinRT therefore does not include EventToCommand. This morning I got a DM from AESIR Consultancy asking me if I had a solution for that, because he had some trouble porting a Windows Phone app to Windows 8. I did not have it then, but I had the feeling it could be done quite easily. In the afternoon, in the time between I came home and my wife came home from work I wrote this behavior that basically does the same as EventToCommand.

And indeed, WinRT does not support behaviors either, but that has been solved already. In order for this to work, you will need to download the NuGet WinRtBehaviors package

Anyway – the behavior. You start out with a project with references to WinRtBehaviors and the Reactive extensions – ReSharper 7 EAP found them readily and automatically attached references to my projects which now has the following references to reactive stuff:

  • System.Reactive.Core
  • System.Reactive.Interfaces
  • System.Reactive.Linq
  • System.Reactive.PlatformServices

So we start out with the class definition and some boring Dependency property definitions:

using System;
using System.Reactive.Linq;
using System.Reflection;
using System.Windows.Input;
using WinRtBehaviors;
using Windows.UI.Xaml;

namespace Win8nl.Behaviors
{
  /// <summary>
  /// A behavior to imitate an EventToCommand trigger
  /// </summary>
  public class EventToCommandBehavior : Behavior<FrameworkElement>
  {

    #region Event

    /// <summary>
    /// Event Property name
    /// </summary>
    public const string EventPropertyName = "Event";

    public string Event
    {
      get { return (string)GetValue(EventProperty); }
      set { SetValue(EventProperty, value); }
    }

    /// <summary>
    /// Event Property definition
    /// </summary>
    public static readonly DependencyProperty 
      EventProperty = DependencyProperty.Register(
        EventPropertyName,
        typeof(string),
        typeof(EventToCommandBehavior),
        new PropertyMetadata(default(string)));

    #endregion

    #region Command

    /// <summary>
    /// Command Property name
    /// </summary>
    public const string CommandPropertyName = "Command";

    public string Command
    {
      get { return (string)GetValue(CommandProperty); }
      set { SetValue(CommandProperty, value); }
    }

    /// <summary>
    /// Command Property definition
    /// </summary>
    public static readonly DependencyProperty 
      CommandProperty = DependencyProperty.Register(
        CommandPropertyName,
        typeof(string),
        typeof(EventToCommandBehavior),
        new PropertyMetadata(default(string)));

    #endregion

    #region CommandParameter

    /// <summary>
    /// CommandParameter Property name
    /// </summary>
    public const string CommandParameterPropertyName = "CommandParameter";

    public object CommandParameter
    {
      get { return (object)GetValue(CommandParameterProperty); }
      set { SetValue(CommandParameterProperty, value); }
    }

    /// <summary>
    /// CommandParameter Property definition
    /// </summary>
    public static readonly DependencyProperty 
        CommandParameterProperty = DependencyProperty.Register(
        CommandParameterPropertyName,
        typeof(object),
        typeof(EventToCommandBehavior),
        new PropertyMetadata(default(object)));

    #endregion
  }
}

All very boring, all very standard. Now, for dynamically adding a listener to the event: I’ve been down this road before, say hello to our friend Observable.FromEventPattern, which takes away all the boring details about the differences between ordinary and WinRT events.

protected override void OnAttached()
{
  var evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
  if (evt != null)
  {
    Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, Event)
      .Subscribe(se => FireCommand());
  }
  base.OnAttached();
}

Nothing special. Try to find an event with the same name as the contents of the “Event” property and add a listener to it. And the final piece of the puzzle is the actual implementation of FireCommand. Of course, I could have implemented this inline but I like to make this a separate method, if only for readability:

private void FireCommand()
{
  var dataContext = AssociatedObject.DataContext;
  if (dataContext != null)
  {
    var dcType = dataContext.GetType();
    var commandGetter = dcType.GetRuntimeMethod("get_" + Command, new Type[0]);
    if (commandGetter != null)
    {
      var command = commandGetter.Invoke(dataContext, null) as ICommand;
      if (command != null)
      {
        command.Execute(CommandParameter);
      }
    }
  }
}

As always, when you know how to do it, it’s very simple. This method gets the AssociatedObject’s data context, the tries to find the getter of the Command property on this data context. As you might remember, a command in MVVMLight is defined like this:

public ICommand DoSomethingCommand
{
  get
  {
    return new RelayCommand<string>((p) =>
        {
          System.Diagnostics.Debug.WriteLine("Hi there {0}", p);
        });
  }
}

so I am not looking for a command method, but for a getter returning a command. If the code finds that, it tries to Invoke the getter as an ICommand. If it gets that it has the actual command, and it executes it. And that’s all!

So if you want to use this behavior, attach it to a Page’s main grid, for instance:

<Grid Style="{StaticResource LayoutRootStyle}" x:Name="TopView" x:Uid="TopGrid">
   <WinRtBehaviors:Interaction.Behaviors>
    <Win8nl_Behavior:EventToCommandBehavior Event="Tapped"
Command="DoSomethingCommand"
CommandParameter="John doe"/> </WinRtBehaviors:Interaction.Behaviors> <!--- stuff in here --> </Grid>

The top of your page needs to include this name space definitions:

xmlns:WinRtBehaviors="using:WinRtBehaviors"
xmlns:Win8nl_Behavior="using:Win8nl.Behaviors"

and then it will work. Tap on the main grid and you will see the text “Hi there John doe” in the Visual Studio output window. Of course you can make it do more useful things too ;-) and you can also bind things to the CommandParameter property using the normal binding syntax. To a certain extent.

You can download the behavior’s code here, but it's actually a lot easier to just use the NuGet Package. The behavior is there, along with some more nice stuff, and it takes care of downloading WinRtBehaviors and Reactive Extensions for WinRT as well

By special request I've also created sample code - not one but two solutions. The first one, TestWin8nl, is a very simple application that allows you to tap a TextBlock - this will trigger a command in the ViewModel that uses Debug.WriteLine to print a property of the ViewModel in your output console windows, using the CommandParameter to transfer the bound object (the ViewModel itself) to the command. The seconds sample, EventToCommandListDemo, will show you how to handle a SelectionChanged event of a ListBox, although frankly I'd rather just bind SelectedItem and act on it's property setter. But the audience asks, the audiences gets ;-). It appears tough as if Element name binding does not work properly in WinRtBehaviors, so I had to use a ViewModel property to store the selected item in anyway. Both are some contrived examples, but I hope the will do the trick of helping you out understanding how things are working and are supposed to be used.

Update: I have also blogged (and published in win8nl) a variant of the behavior that takes a bound command in stead of a command name. I personally now think this is a better solution as it adheres more to the way regular behaviors work, and is much more flexible Update 2: both this behavior and it's the bound-command-behavior are in the win8nl nuget package. Don't type, be lazy, use Nuget ;-)

23 July 2012

Using a provisional WinRT port of SilverlightSerializer to store state in MVVMLight ViewModels

Over 1.5 years ago I showed how to store your Windows Phone application state (‘tombstoning’) using SilverlightSerializer by Mike Talbot. In my quest to leverage hard-won Windows Phones skills to be usable in Windows 8 I made a provisional port of SilverlightSerializer 1 to WinRT. That is, in C#.

Since my win8nl library port is a bit behind, I’ve stuck the class in a simple project that you can download here.

Usage is as follows: in App.xaml.cs, you define two methods: SaveState and RestoreState:

private async void SaveState()
{
  var file = 
    await ApplicationData.Current.LocalFolder.CreateFileAsync(
      "AppState.dat", CreationCollisionOption.ReplaceExisting);

  using (var fileStream = await file.OpenStreamForWriteAsync())
  {
    SilverlightSerializer.Serialize(MainViewModel.Instance, fileStream);
  }
}

Pretty simple: when the state needs to be saved, create a file, get a stream, and let SilverlightSerializer do its magic. As for RestoreState:

private async Task RestoreState()
{
  try
  {
    var files = await ApplicationData.Current.LocalFolder.GetFilesAsync();
    var dataFile = files.FirstOrDefault(p => p.Name == "AppState.dat");
    if (dataFile != null)
    {
      using (var fileStream = await dataFile.OpenSequentialReadAsync())
      {
        MainViewModel.Instance = 
          SilverlightSerializer.Deserialize(fileStream.AsStreamForRead()) 
            as MainViewModel;
      }
    }
  }
  finally
  {
    if (MainViewModel.Instance == null) MainViewModel.CreateNew();
    MainViewModel.Instance.Start();
  }
}

This basically tries to deserialize a viewmodel from a file “AppState.dat”. If that fails, it creates a new MainViewModel, and starts it. The whole idea behind this is described in the original Windows Phone 7 post, so I encourage you to read that if you have no idea what I am doing here.

Now the important bit is when to call this methods. If you think the most logical place for RestoreState is in OnLaunched, you are right. The first few lines of my OnLaunced method in App.xaml.cs look like this in my app:

if (args.PreviousExecutionState == ApplicationExecutionState.Running)
{
  Window.Current.Activate();
  return;
}
else
{
  await RestoreState();
}

Now the most logical place to call SaveState is of course OnSuspending, and we are done, right?

Wrong.

To my own utter surprise, yesterday, after a long debugging session, I found a weird edge scenario. I asserted the following: if a user closes an app by the “Swipe Down gesture”, it takes about 10 seconds (on my Samsung Slate 7) before OnSuspending is called. When the user restarts the app within those 10 seconds from the start screen, the state is not stored yet, or too late – in any case it is not yet available to the (yet again) starting app. So you don’t get the last state, but the state before that, as I shamefully discovered when I proudly showed my state save method to an Application Excellence Lab Microsoftie :(

Don’t get me wrong – the actual time SaveState runs in my app is about 0.047 seconds. It’s lightning fast – just like the original SilverlightSerializer. But the time between user closing the app and the actual state save being fired up was killing my state.

The solution to this is very simple: when the user closes the app, Window.Current.VisibilityChanged is fired. Not like after a few seconds, but instantly. So add and event listener to that at the bottom of OnLaunched, that calls SaveState , like this:

 Window.Current.VisibilityChanged += (o, e) => {if (!e.Visible) SaveState();};

Basically: if the visibility of the current windows changes to invisible, write the state. Maybe you write app state too often (for example because the user temporarily puts it in the background, then VisibilityChanged is fired as well) but at least you circumvent the problem I ran into. Since state writing takes very little time, better often than not at all, I’d say.

And in OnSuspending? Well, you could call SaveState from there, too. That’s useful when your app does something in the background and it’s state changes even when the users has put it in the background. Then, when the OS kicks it into suspension because it runs out of memory, the state is saved too.

Caveat emptor: I kinda roughly hacked Mike Talbots work to operate in the WinRT world. The current state is ‘works for me’. I commented out the whole section about Dictionary support, so I suppose that does not work. My ultimate goal is to convert SilverlightSerializer 2, but that was too big a bone to chew in a short time. It serves my ported game Catch’em Birds fine. I hope to get it finished soon.