17 October 2010

Browse the Marketplace for Windows Phone 7 apps outside the USA

This article does technically not belong to this blog, for it does not contain any code samples – in fact it does not handle code at all. But since the launch of Windows Phone 7 is a very special occasion and the devices will hit my country (the Netherlands) very soon I thought it important enough to break rank for once.

For all kinds of reasons – mostly legal, I’ve been told - about 17 countries are included in the Marketplace for Windows Phone 7. This by no means that you cannot be part of the fun of the Windows Phone 7 launch if you are not inside the USA or any of the other countries – like me. All you have to do to view the Windows Phone 7 apps that are currently in the Marketplace is follow the simple procedure below:

  1. Install Zune software (if you haven’t done that already)
  2. Browse to www.msn.com. This will redirect you to your local msn (in my case, nl.msn.com) but will also provide you with a popup that lets you choose between your local msn.com and the USA msn.com. Choose the USA version
  3. If you are signed in with your live ID, sign out
  4. Create a new live ID that has its location in the USA. You need to provide an USA state and ZIP code that actually exist and match. Which can be easily obtained via this site. Simply click somewhere on the map, choose one of the cities it suggests, and presto – one existing zip code and state combination
  5. Start up the Zune software
  6. Login with your freshly created live ID
  7. Provide your birth date
  8. Click Marketplace
  9. Click Apps
  10. And there you are

Update according to Rob Houweling this procedure will only work if the OS language is set to English. See comment. Thanks Rob!

Update 2 this works on a Windows Phone 7 as well. Tom Verhoeff has a blog post which explains (in Dutch) how you can setup a phone to use a specific Live Id that has it's location in the UK and a billing adress in the UK that will allow you to buy apps using an ordinary Dutch credit card.

Bear in mind that your local Microsoft office does not support this procedure, so when you have problems you are basically on your own. But that is what you have your local Microsoft community for - they can probably help you out, and if not, there are plenty of Microsoft employees who will help you out sub rosa – if you just ask the right person kindly enough. After all, we’re all in the same boat ;-)

Have fun!

06 October 2010

Using MVVMLight Messenger and behaviors to open files from local disk in Silverlight

The very first Silverlight application I had to make professionally (i.e. not as a hobby/research project at home) required the possibility to open a file from (local) disk. Of course I wanted to use Laurent Bugnion’s MVVMLight and the strict separation between logic that I talked and blogged about so much – ‘practice what thou preach’, eh?

This proved to be an interesting challenge. The most logical way forward seemed to be: make a button, attach a command to it via the usual EventToCommand route and then use OpenFileDialog from the model – which landed me a “Dialogs must be user-initiated” error. Googling Binging around I found out that Dennis Vroegop had run into this thingy quite recently as well.

Things looked ugly. Getting around it took me some code in the code behind. This kept nagging me, and only recently I found a better way to deal with this. Apart from the EventToCommand binding MVVMLight contains another gem, called the Messenger. This is an implementation of the Mediator pattern that - as far as I understand – is designed to broadcast property changes between different models in the application. But this mechanism can also be used as an alternative way to shuttle data from the GUI to the model in a designer-friendly – Blendable -way. The way to go for this particular problem is like this:

  • Define a message that holds the data from an OpenFileDialog
  • Make a behavior that can attach to a button that launches an OpenFileDialog on click, and then sends a message on the Messenger
  • Register a listener on the Messenger in the model for that particular message

True to my blog’s title, I will demonstrate this principle with an example. First, a message containing the result of an OpenFileDialog:

using System.Collections.Generic;
using System.IO;
using GalaSoft.MvvmLight.Messaging;

namespace LocalJoost.Behaviours
{
  public class FilesOpenedMessage : GenericMessage<IEnumerable<FileInfo>>
  {
    public FilesOpenedMessage(IEnumerable<FileInfo> parm)
      : base(parm)
    {
      Identifier = string.Empty;
    }

    public string Identifier{get;set;}
  }
}

Notice that the message also contains a property Identifier, acting like an optional additional message identifier. This is necessary, since the MVVMLight messenger seems to identify messages by type. Therefore, every method listening to a FilesOpenedMessage gets a message, and the various models would have no way to know if it was actually for them to act on it. Identifier makes coupling a particular listener to a particular sender possible. I’m sure there are other ways to get this done, I simply chose the simplest.

Getting on with the behavior:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using GalaSoft.MvvmLight.Messaging;

namespace LocalJoost.Behaviours
{
  /// <summary>
  /// A behavior attaching to a button
  /// </summary>
  public class FileOpenBehavior : Behavior<Button>
  {
    // Properties - can be set from XAML
    public string MessageIdentifier { get; set; }
    public string Filter { get; set; }
    public bool MultiSelect { get; set; }

    protected override void OnAttached()
    {
      base.OnAttached();
      Filter = "All files (*.*)|*.*";
      AssociatedObject.Click += AssociatedObject_Click;
    }

    void AssociatedObject_Click(object sender, RoutedEventArgs e)
    {
      // Open the dialog and send the message
      var dialog = 
        new OpenFileDialog {Filter = Filter, Multiselect = MultiSelect};
      if (dialog.ShowDialog() == true)
      {
        Messenger.Default.Send(
          new FilesOpenedMessage(dialog.Files) 
          { Identifier = MessageIdentifier });
      }      
    }

    protected override void OnDetaching()
    {
      AssociatedObject.Click -= AssociatedObject_Click;
      base.OnDetaching();
    }
  }
}

Which works pretty simple: it attaches itself to the click event, composes a message and fires it away on the Messenger. In your model you register a listener like this:

public class DemoModel : ViewModelBase
{
  public DemoModel()
  {
    if (IsInDesignMode)
    {
      // Code runs in Blend --> create design time data.
    }
    else
    {
      Messenger.Default.Register<FilesOpenedMessage>(
        this,
        DoOpenFileCallback);
    }
  }

  private void DoOpenFileCallback(FilesOpenedMessage msg)
  {
    if (msg.Identifier != "1234") return;
    // Store result in SelectedFiles
    SelectedFiles = msg.Content.Select(f => f.Name).ToList();
  }
  // Rest of model omitted - see demo solution
}

The “Content” property of the message always contains the payload, i.e. whatever you had to pass to the message constructor – in this case, an IEnumerable<FileInfo>. In XAML you then bind the whole thing together like this, like any ordinary behavior:

<UserControl x:Class="DemoMessageBehaviour.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:model="clr-namespace:DemoMessageBehaviour.Model;assembly=DemoMessageBehaviour.Model"
  xmlns:LJBehaviours="clr-namespace:LocalJoost.Behaviours;assembly=LocalJoost.Behaviours"
  xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"        
  mc:Ignorable="d"
  d:DesignHeight="300" d:DesignWidth="400">
  <UserControl.Resources>
    <model:DemoModel x:Key="MyDemoModel"/>
  </UserControl.Resources>
  <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource MyDemoModel}">
    <Grid.RowDefinitions>
      <RowDefinition Height="0.9*"/>
      <RowDefinition Height="0.1*"/>
    </Grid.RowDefinitions>
    <Button Content="Open" Grid.Row="1" IsEnabled="{Binding CanOpen}" >
      <i:Interaction.Behaviors>
        <LJBehaviours:FileOpenBehavior MessageIdentifier="1234" MultiSelect="True"/>
      </i:Interaction.Behaviors>
    </Button>
    <ListBox Grid.Row="0" ItemsSource="{Binding SelectedFiles}"/>
  </Grid>
</UserControl>

The Listbox is used to display the names of the selected files. I did leave this out, there’s enough code in this sample already. For those who want to have the full picture: a complete solution demonstrating the behavior can be found here.

Notice there’s an important difference using this technique in stead of the EventToCommand: when the user presses the button, the model cannot control the actual display of the OpenFileDialog: the click is handled by the behavior, not the model itself (via EventToCommand) and the OpenFileDialog is always displayed once the button is clicked. Therefore, the model should control if the user can press the button at all, which is done by binding the IsEnabled property to a property of the model (CanOpen – sorry, lame pun). Which is good UX practice anyway – controls that cannot be used should be disabled in stead of giving a ‘sorry, you can’t do that’ message whenever possible, but in this case it’s simply necessary.

I only showed how to do open a file from disk, but a pattern like this can be used to save files to disk as well, or do other things that might seem to require coding in the code behind file. That is no sin in itself – nobody from the MVVM police will show up at your doorstep and take your family away if you need to do that. At least that is what Laurent himself promised at his MIX10 talk ;-). But by coding a behavior, you enable designers to add fairly easily relatively complex actions using Blend without having to dive too deep into XAML. Using behaviors like this FileOpenBehavior makes it even easier to add interactivity than the EventToCommand (which was closed off anyway during security restrictions).

It can’t hurt to be nice to your designers – after all, they make the pretty stuff up front that makes your application sell ;-)

Oh, and one final thing: in all my previous posts I was talking about ‘behaviour’ in stead of ‘behavior’. I hope you all will excuse me for being educated in the Queen’s English, even tough I am just Dutch. ;-).

30 September 2010

Notifying the viewmodel of input errors using MVVMLight in Silverlight

I was creating a little application that had some input fields and a submit button. I wanted the submit button only to be enabled when the user input was valid. No a very unusual use case. So I set out to create a viewmodel the usual MVVMLight way, extending ViewModelBase and making properties using the snippets Laurent Bugnion provides with the MVVMLight toolkit. To validate them, I decorated them with attributes from System.ComponentModel.DataAnnotations, and validated them with using the Validator. A typical property looks like this:

/// 
/// The  property's name.
/// 
public const string SomecodePropertyName = "Somecode";

private int _somecode = 0;

[Range(0, 2000)]
public int Somecode
{
  get
  {
    return _someCode;
  }

  set
  {
    if (_someCode == value)
    {
      return;
    }
    Validator.ValidateProperty(value,
      new ValidationContext(this, null, null) 
      { MemberName = SomecodePropertyName });

    _someCode = value;

    // Update bindings, no broadcast
    RaisePropertyChanged(SomecodePropertyName);
  }
}

Then I thought I was smart, so I added the following code:

private void RaisePropertyChangedAndRevalidate(string propertyName)
{
  RaisePropertyChanged(propertyName);
  RaisePropertyChanged("IsValid");
}

public bool IsValid
{
  get
  {
    return Validator.TryValidateObject(this, 
                       new ValidationContext(this, null, null),
                       new List<ValidationResult>());
  }
}

and changed every other call to RaisePropertyChanged to RaisePropertyChangedAndRevalidate. Then I bound my button’s IsEnabled property to IsValid

<Button Content="subMit" x:Name="btnSave" 
  IsEnabled="{Binding IsValid,ValidatesOnExceptions=True,NotifyOnValidationError=True}">

and I turned out not be so very smart after all, for it did not work. When the user entered a value that was outside the range of 0-2000 or even plain nonsense – like “thisisnonumber”, the UI gave an error message, I even got the message in my ValidationSummary, but for some reason the viewmodel still found itself valid.

This puzzled me for a while, but it turned out to be perfectly logical. If the user inputs nonsense this throws an exception, and so does a call to Validator.ValidateProperty. So the invalid input never makes to the viewmodel property, and the viewmodel, if it was initially valid, stays valid en thus my button stays enabled. How to get around this?

Actually, it’s pretty simple: notify your viewmodel of input errors, so it can keep track of whatever nonsense the user has tried to cram down its throat. The way I chose to do it was like this:

  • Add a field int _fieldErrors;
  • Bind the event BindingValidationError to a command in the viewmodel, passing it’s parameters along
  • Add to or subtract 1 from_fieldErrors for every time the command was called depending on the parameter
  • Modify the IsValid property so it checks the _fieldErrors field to.

In code:

private void RaisePropertyChangedAndRevalidate(string propertyName)
{
  RaisePropertyChanged(propertyName);
  if (_fieldBindingErrors == 0)
  {
    RaisePropertyChanged("IsValid");
  }           
}
private int _fieldBindingErrors = 0;

public ICommand RegisterFieldBindingErrors
{
  get
  {
    return new RelayCommand<ValidationErrorEventArgs>(e =>
    {
      if (e.Action == ValidationErrorEventAction.Added)
      {
        _fieldBindingErrors++;
      }
      else
      {
        _fieldBindingErrors--;
      }
      RaisePropertyChanged("IsValid");
    });
  }
}

public bool IsValid
{
  get
  {
    return Validator.TryValidateObject(this, 
                       new ValidationContext(this, null, null),
                       new List<ValidationResult>()) 
                       && _fieldBindingErrors == 0;
  }
}

Binding the stuff in XAML goes like this:

<StackPanel
  DataContext="{Binding MyModel,Mode=TwoWay,ValidatesOnExceptions=True,NotifyOnValidationError=True}">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="BindingValidationError">
          <cmd:EventToCommand Command="{Binding RegisterFieldBindingErrors}" 
            PassEventArgsToCommand="true"/>
        </i:EventTrigger>
      </i:Interaction.Triggers>
</StackPanel>

And thus the viewmodel maintains its own integrity, is notified by the UI of all problems playing around there, and can decide based upon the sum of this information whether or not the user can actually save.

Thanks to Mike Taulty for helping me out on the Validator in real-time on Twitter.

29 September 2010

Extension methods for tomb stoning the Windows Phone 7 model

As I was (and still am) playing with my MVVM-driven Windows Phone 7 map viewer, I started thinking about tomb stoning and/or serializing stuff into the Windows Phone 7 application state and/or isolated storage. I came up with four extension methods than can be used to store/serialize the complete model in both. Maybe not ideal in all cases, but it was a simple solution for me.

Getting started

I created an assembly LocalJoost.Utilities, in which I first defined a generic interface for the model, which I called – with a flash of inspiration – IModel ;-). It’s implementation is not interesting for the extension methods.

Save to phone application state

using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Windows;
using Microsoft.Phone.Shell;

namespace LocalJoost.Utilities
{
  /// <summary>
  /// Some extensions method that allow serializing and deserializing
  /// a model to and from phone state and/or isolated storage
  /// </summary>
  public static class ApplicationExtensions
  {
    private const string ModelKey = "model";
 
    public static IModel RetrieveFromPhoneState(this Application app) 
    {
      if (PhoneApplicationService.Current.State.ContainsKey(ModelKey))
      {
        return PhoneApplicationService.Current.State[ModelKey] as IModel;
      }
      return null;
    }

    public static void SaveToPhoneState(this Application app, IModel model)
    {
      if (PhoneApplicationService.Current.State.ContainsKey(ModelKey))
      {
        PhoneApplicationService.Current.State.Remove(ModelKey);
      }
      PhoneApplicationService.Current.State.Add(ModelKey, model);
    }
  }
}

Creating a Locator

I wanted my model to be bindable by XAML and be usable from code as well, so I created the following ‘Locator’:

using LocalJoost.Utilities;

namespace LocalJoost.Models
{
  public class Locator
  {
    private static IModel _model;
    private static Locator _locator;

    public IModel Model
    {
      get { return _model; }
      set { _model = value; }
    }

    public static Locator Instance
    {
      get { return _locator ?? (_locator = new Locator()); }
    }
  }
}

Using Locator and Model from XAML

First, add the namespace to the XAML

xmlns:Utilities="clr-namespace:LocalJoost.Utilities;assembly=LocalJoost.Utilities"

Then bind it to your Layout root or any other element of choice

 <Grid x:Name="LayoutRoot"
  DataContext="{Binding Source={StaticResource Locator}, Path=Model}">

Instantiating your model

Interesting caveat – the Locator is instantiated, not your model. When the application runs for the very first time, there will be no model to retrieve. Thus, in the constructor of App.Xaml.cs you need to add:

Locator.Instance.Model = new YourModel();

in which you replace "YourModel" for your own model type.

Storing in / retrieving from phone application state

Using the extension methods is pretty simple then: open your App.Xaml.cs, find two methods called “Application_Activated” and “Application_Deactivated” and modify them as follows:

// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
  Locator.Instance.Model = this.RetrieveFromPhoneState();
}

// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
  this.SaveToPhoneState(Locator.Instance.Model);
}

And that’s it. Your model now persists to the phone state and survives, for instance, a hit on the search button

Storing in Isolated Storage

This proves to be marginally more difficult. I expanded the class ApplicationExtensions with two more methods and a const:

private const string DataFile = "model.dat";

public static T RetrieveFromIsolatedStorage<T>(this Application app) 
  where T : class
{
  using (var appStorage = IsolatedStorageFile.GetUserStoreForApplication())
  {
    if (appStorage.FileExists(DataFile))
    {
      using (var iss = appStorage.OpenFile(DataFile, FileMode.Open))
      {
        try
        {
          var serializer = new DataContractSerializer(typeof(T));
          return serializer.ReadObject(iss) as T;
        }
        catch (Exception e)
        {
          System.Diagnostics.Debug.WriteLine(e);
        }
      }
    }
  }
  return null;
}

public static void SaveToIsolatedStorage(this Application app, IModel model)
{
  using (var appStorage = IsolatedStorageFile.GetUserStoreForApplication())
  {
    if (appStorage.FileExists(DataFile))
    {
      appStorage.DeleteFile(DataFile);
    }
    var serializer = new DataContractSerializer(model.GetType());
    using (var iss = appStorage.CreateFile(DataFile))
    {
      serializer.WriteObject(iss, model);
    }
  }
}

You now have to find Application_Launching and Application_Closing in App.Xaml.cs and modify them in a similar way:

// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
    Locator.Instance.Model = 
       this.RetrieveFromIsolatedStorage<YourModel>();
}

// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
    this.SaveToIsolatedStorage(Locator.Instance.Model);
}

Some notes

  • In order to make this work, your need to mark your model class with the [DataContract] attribute, and every member you want to be serialized with [DataMember]
  • If you are using MVVMLight (which of course you are ;-) ) and if you are just making simple apps that don’t use separate models but just view models, be aware that your model cannot inherit from ViewModelBase, for the simple reason that this class is not serializable. Oops ;-)
  • If your model communicates with the view using attached dependency properties you may run into some timing difficulties. I will soon blog about a work-around for that.

10 September 2010

An animated swipe-enabled title control for Windows Phone 7

Updated for the RTM tools, included sample application to show how it’s used.

For my ongoing ‘research project’ on making the user experience for my MVVM-driven map viewer for Windows Phone 7 a bit better I wanted to make some changes to the header. Initially you could swipe the header which showed which map you show, but it gave no indication that you actually could make the swipe, or that other maps were available. I set out to create a behaviour, and ended up building a control. In my map viewer, it currently looks and works like this:

And, of course, it needed to play along nicely with MVVM. And therefore it has three bindable properties:

  • Items: an IList of basically anything
  • SelectedItem: the currently selected item in Items
  • DisplayText: (optional): the name property of the objects in Items which value should be used in de SwipeTitle. If skipped, the ToString() value of the objects is used as a display value.

It does not sport item or data templates (yet) – it’s just meant to be plug and play. For now.

Usage

You only have to do six things to use this thing:

  • Create an empty Windows Phone 7 application
  • Add the LocalJoost.Controls project included in the demo solution to your project.
  • Create some kind of model with a property containing a list of objects and a property containing a selected object and bind it to the layout root
  • Drag the SwipeTitle control on the design surface at the place of the TextBox called “PageTitle” (and remove PageTitle)
  • Bind property Items, SelectedItem and DisplayText as needed
  • Make sure the Width property of the StackPanel “TitlePanel” is some large width, e.g. 2000.

Below is a short walkthrough of the source. Those who just want to use it, can just grab the source. If you want a simple sample application showing the usage of the control, just grab this solution and see how it works. I sincerely apologize for the sheer silliness of the demo solution, it was all I could think of on short notice.

Walkthrough

The XAML is pretty simple: three TextBlocks in a horizontal StackPanel:

<UserControl x:Class="WP7Viewer.SwipeTitle"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d"
  FontFamily="{StaticResource PhoneFontFamilyNormal}"
  FontSize="{StaticResource PhoneFontSizeNormal}"
  Foreground="{StaticResource PhoneForegroundBrush}"
  d:DesignHeight="480" d:DesignWidth="480">
    <StackPanel Grid.Row="1" Orientation="Horizontal" x:Name="pnlSwipe">
      <TextBlock x:Name="tbPrevious"
          Foreground="Gray"
           Text="Previous" 
           Margin="0,0,0,0"
           Style="{StaticResource PhoneTextTitle1Style}">
      </TextBlock>
    <TextBlock x:Name="tbCurrent"
           Text="Current" 
           Margin="20,0,0,0"
           Style="{StaticResource PhoneTextTitle1Style}">
       </TextBlock>
    <TextBlock x:Name="tbNext"
          Foreground="Gray"
           Text="Next" 
           Margin="20,0,0,0"
           Style="{StaticResource PhoneTextTitle1Style}">
      </TextBlock>
    </StackPanel>
</UserControl>

You can swipe endlessly left or right, when it comes to the end or the start of the list it just adds the items from the start or the end again. The middle text is the selected object, and is always shown (in white). When you swipe the text to the left, it animates the swipe to completion: the text previously on the right, which you swiped into view, is now displayed in the middle TextBlock. The text that used to be in the middle block, is now in the left, and in the right TextBlock a new text from Items is displayed, as shown in the video.

Now how does this work? If you know how to do it, it is – as everything – pretty simple. First, some boring stuff, the class definition with some members and dependency properties:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace WP7Viewer
{
    public partial class SwipeTitle
    {
       /// <summary>
       /// An internal linked list to make searching easier
       /// </summary>
       private LinkedList<object> _displayItems;
       private TranslateTransform _transform;
       private int _currentDisplayItem = 1; 
     
      #region Items
      /// <summary>
      /// Dependency property holding the items selectable in this control
      /// </summary>
      public static readonly DependencyProperty ItemsProperty =
         DependencyProperty.Register("Items", typeof(IList),
         typeof(SwipeTitle), new PropertyMetadata(ItemsChanged));

      private static void ItemsChanged(object sender, 
        DependencyPropertyChangedEventArgs args)
      {
        var c = sender as SwipeTitle;
        if (c != null) {  c.ProcessItemsChanged(); }
      }

      public IList Items
      {
        get { return (IList)GetValue(ItemsProperty); }
        set { SetValue(ItemsProperty, value); }
      }

      public void ProcessItemsChanged()
      {
        _displayItems = new LinkedList<object>();
        foreach (var obj in Items) _displayItems.AddLast(obj);
        SelectedItem = Items[0];
      }
      #endregion

      #region SelectedItem
      /// <summary>
      /// Dependency property holding the currently selected object
      /// </summary>
      public static readonly DependencyProperty SelectedItemProperty =
         DependencyProperty.Register("SelectedItem", typeof(object),
         typeof(SwipeTitle), new PropertyMetadata(SelectedItemChanged));

      private static void SelectedItemChanged(object sender, 
        DependencyPropertyChangedEventArgs args)
      {
        var c = sender as SwipeTitle;
        if (c != null) { c.ProcessSelectedItemChanged(); }
      }

      // .NET Property wrapper
      public object SelectedItem
      {
        get { return (object)GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
      }

      public void ProcessSelectedItemChanged()
      {
        UpdateDisplayTexts();
        ScrollToDisplayItem(1, false);
      }
      #endregion
      
      #region DisplayField
      public string DisplayField
      {
        get { return (string)GetValue(DisplayFieldProperty); }
        set { SetValue(DisplayFieldProperty, value); }
      }

      public static readonly DependencyProperty DisplayFieldProperty =
        DependencyProperty.Register("DisplayField", typeof(string), 
          typeof(SwipeTitle), null);
      #endregion
    }
  }
}

The transformation is used in the animation and to make sure the middle TextBlock is displayed when idle. I tend to tuck dependency properties in regions to keep stuff a bit organized, but feel free to do otherwise. Note, however, that the objects in Items are immediately copied in a LinkedList _displayItems – I use this list to make it easier to find previous and next objects.

Then we need a little method to get the display text from the objects according to the value of “DisplayField”:

/// <summary>
/// Retrieve the display value of an object
/// </summary>
/// <param name="displayObject"></param>
/// <returns></returns>
private string GetDisplayValue( object displayObject)
{
  if (DisplayField != null)
  {
    var pinfo = displayObject.GetType().GetProperty(DisplayField);
    if (pinfo != null)
    {
      return pinfo.GetValue(displayObject, null).ToString();
    }
  }
  return displayObject.ToString();
}
To show or update the displayed texts, according the object that is selected (in SelectedItem), the UpdateDisplayTexts method is needed. This is fired when Items or SelectedItem is changed. It finds SelectedItem and puts it in the middle TextBlock, and finds the texts that need to be before and after it, using the LinkedList _displayItems.
/// <summary>
/// Shows (possible) new texts in the three text boxes
/// </summary>
private void UpdateDisplayTexts()
{
  if (_displayItems == null) return;
  if (SelectedItem == null)
  {
    SelectedItem = _displayItems.First.Value;
  }
  tbCurrent.Text = GetDisplayValue(SelectedItem);
  var currentNode = _displayItems.Find(SelectedItem);
  if (currentNode == null) return;
  tbNext.Text =
    GetDisplayValue(currentNode.Next != null ? 
     currentNode.Next.Value : _displayItems.First.Value);
  tbPrevious.Text =
    GetDisplayValue(currentNode.Previous != null ? 
     currentNode.Previous.Value : _displayItems.Last.Value);
}

Now I need to set up and implement some events in the control:

  • The items must be initially displayed, after the control is loaded
  • When the user swipes the title, it must follow his finger
  • When the user stops swiping, it must decide whether the user has swiped far enough to select the next item (and if not, revert the swipe), and if the swipe was far enough, select the next item
  • When the next item is selected, show the new selected text in the middle again.
public SwipeTitle()
{
    InitializeComponent();
    _transform = new TranslateTransform();

    pnlSwipe.Loaded += (sender, args) => ProcessSelectedItemChanged();
    pnlSwipe.ManipulationDelta += pnlSwipe_ManipulationDelta;
    pnlSwipe.ManipulationCompleted += pnlSwipe_ManipulationCompleted;
    pnlSwipe.RenderTransform = _transform;
    tbPrevious.SizeChanged += tbPrevious_SizeChanged;
}

void pnlSwipe_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
    _transform.X += e.DeltaManipulation.Translation.X;
}

/// <summary>
/// Caculates the screen width
/// </summary>
private static double ScreenWidth
{
    get
    {
        var appFrame = Application.Current.RootVisual as Frame;
        return null == appFrame ? 0.0 : appFrame.RenderSize.Width;
    }
}

/// <summary>
/// Fired after manipulation is completed. When the title has been moved over 25% of the
/// screen, the next or previous item is selected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void pnlSwipe_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
    if (e.TotalManipulation.Translation.X > .25 * ScreenWidth)
    {
        ScrollToDisplayItem(_currentDisplayItem - 1, true);
    }
    else if (e.TotalManipulation.Translation.X < -.25 * ScreenWidth)
    {
        ScrollToDisplayItem(_currentDisplayItem + 1, true);
    }
    ScrollToDisplayItem(_currentDisplayItem, true);
}

/// <summary>
/// Fired when new data is put into the last object. 
/// Rendering is then finished - the middle text is showed in the middle again
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void tbPrevious_SizeChanged(object sender, SizeChangedEventArgs e)
{
    ScrollToDisplayItem(1, false);
}

In the constructor the members are initialized – particularly the transform – which is set to the StackPanel surrounding the three TextBlocks. When the user now swipes, the texts appear to follow him. When, in pnlSwipe_ManipulationCompleted, the user has dragged the text over more than 25% of the screen, it scrolls the text further until the newly selected items is fully into view. If the text value of the last box is changed, we need to reset the middle TextBlock in the center again – but now without animation, and so it will seem if the scrolling text suddenly changes in color and appears to be selected.

Notice a little gem in here – the ScreenWidth property. It turns out you can determine the actual screensize by trying to cast the RootVisual to a Frame, and then check it’s RenderSize.

All that is left now, basically, is the implementation of ScrollToDisplayItem – and a companion method, as shown below:

/// <summary>
/// Scrolls to one of the 3 display items
/// </summary>
/// <param name="item">0,1 or 2</param>
/// <param name="animate">Animate the transition</param>
void ScrollToDisplayItem(int item, bool animate)
{
  _currentDisplayItem = item;
  if (_currentDisplayItem < 0) _currentDisplayItem = 0;
  if (_currentDisplayItem >= pnlSwipe.Children.Count)
  {
    _currentDisplayItem = pnlSwipe.Children.Count - 1;
  }
  var totalTransform = 0.0;
  for (var counter = 0; counter < _currentDisplayItem; counter++)
  {
    double leftMargin = 0;
    if (counter + 1 < pnlSwipe.Children.Count)
    {
      leftMargin = 
        ((Thickness)(pnlSwipe.Children[counter + 1].GetValue(MarginProperty))).Left;
    }
    totalTransform += 
      pnlSwipe.Children[counter].RenderSize.Width + leftMargin;
  }
  var whereDoWeGo = -1 * totalTransform;

  if (animate)
  {
    //Set up the storyboard and animate the transition
    var sb = new Storyboard();
    var anim = 
      new DoubleAnimation
      {
        From = _transform.X,
        To = whereDoWeGo,
        Duration = new Duration(
          TimeSpan.FromMilliseconds(Math.Abs(_transform.X - whereDoWeGo)))
      };
    Storyboard.SetTarget(anim, _transform);
    Storyboard.SetTargetProperty(anim, new PropertyPath(TranslateTransform.XProperty));
    sb.Children.Add(anim);
    sb.Completed += sb_Completed;
    sb.Begin();
  }
  else
  {
    _transform.X = whereDoWeGo;
  }
}

/// <summary>
/// Fired when an animation is completed. Then a new items must be selected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void sb_Completed(object sender, EventArgs e)
{
  if (SelectedItem != null)
  {
    var currentNode = _displayItems.Find(SelectedItem);
    if (_currentDisplayItem == 0)
    {
      SelectedItem = (currentNode.Previous != null ? 
                       currentNode.Previous.Value : _displayItems.Last.Value);
    }
    if (_currentDisplayItem == 2)
    {
      SelectedItem = (currentNode.Next != null ? 
                       currentNode.Next.Value : _displayItems.First.Value);
    }
    UpdateDisplayTexts();
  }
}

In ScrollToDisplayItem the text is either moved or animated in the right direction, and when the animation is finished, the TextBlocks are updated with values according to the swipe direction. If no animation is needed – which occurs initially, or after the texts are updated – the transform is simply applied in stead of animated.

Credits

Important parts of the code came into being during a joint hacking evening at Sevensteps in Amersfoort, Netherlands, at August 31 2010. My sincere thanks to Bart Rozendaal, Kees Kleimeer and Pieter-Bas IJdens, all of Sevensteps, who basically coded the method pnlSwipe_ManipulationCompleted and the property ScreenWidth, almost all of the ScrollToDisplayItem method, and in addition supported me with wine, snacks and enjoyable company during that memorable evening.

08 August 2010

A Windows Phone 7 multi touch pan/zoom behaviour for Multi Scale Images

Some may have read my foray into using Windows Phone 7 to view maps, utilizing a Multi Scale Image (msi), MVVM Light and some extension properties. This application works quite well, but being mainly a study in applied architecture, the user experience leaves much to be desired. Studying Laurent Bugnion’s Multi Touch Behaviour got me on the right track. Although Laurent’s behaviour is very good, it basically works by translating, resizing (and optionally rotating) the control(s) inside the FrameworkElement is is attached to. For various reasons this is not an ideal solution for a map viewer.

So I set out to make my own behaviour, the first one I ever made by the way, and it turned out to remarkably easy – less than 90 lines of code, including whitespace and comments:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace LocalJoost.Behaviours
{
  /// <summary>
  /// A behaviour for zooming and panning around on a MultiScaleImage
  /// using manipulation events
  /// </summary>
  public class PanZoomBehaviour : Behavior<MultiScaleImage>
  {
    /// <summary>
    /// Initialize the behavior
    /// </summary>
    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.ManipulationStarted += AssociatedObject_ManipulationStarted;
      AssociatedObject.ManipulationDelta += AssociatedObject_ManipulationDelta;
    }
    /// <summary>
    /// Shortcut for the Multiscale image
    /// </summary>
    public MultiScaleImage Msi { get { return AssociatedObject; } }

    /// <summary>
    /// Screen point where the manipulation started
    /// </summary>
    private Point ManipulationOrigin { get; set; }

    /// <summary>
    /// Multiscale view point origin on the moment the manipulation started
    /// </summary>
    private Point MsiOrigin { get; set; }

    void AssociatedObject_ManipulationStarted(object sender,
ManipulationStartedEventArgs e) { // Save the current manipulation origin and MSI view point origin MsiOrigin = new Point(Msi.ViewportOrigin.X, Msi.ViewportOrigin.Y); ManipulationOrigin = e.ManipulationOrigin; } void AssociatedObject_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) { if (e.DeltaManipulation.Scale.X == 0 && e.DeltaManipulation.Scale.Y == 0) { // No scaling took place (i.e. no multi touch) // 'Simply' calculate a new view point origin Msi.ViewportOrigin = new Point { X = MsiOrigin.X - (e.CumulativeManipulation.Translation.X / Msi.ActualWidth * Msi.ViewportWidth), Y = MsiOrigin.Y - (e.CumulativeManipulation.Translation.Y / Msi.ActualHeight * Msi.ViewportWidth), }; } else { // Multi touch - choose to interpretet this either as zoom or pinch var zoomscale = (e.DeltaManipulation.Scale.X + e.DeltaManipulation.Scale.Y) / 2; // Calculate a new 'logical point' - the MSI has its own 'coordinate system' var logicalPoint = Msi.ElementToLogicalPoint( new Point { X = ManipulationOrigin.X - e.CumulativeManipulation.Translation.X, Y = ManipulationOrigin.Y - e.CumulativeManipulation.Translation.Y } ); Msi.ZoomAboutLogicalPoint(zoomscale, logicalPoint.X, logicalPoint.Y); if (Msi.ViewportWidth > 1) Msi.ViewportWidth = 1; } } /// <summary> /// Occurs when detaching the behavior /// </summary> protected override void OnDetaching() { AssociatedObject.ManipulationStarted -= AssociatedObject_ManipulationStarted; AssociatedObject.ManipulationDelta -= AssociatedObject_ManipulationDelta; base.OnDetaching(); } } }

Method AssociatedObject_ManipulationStarted just records where the user started the manipulation, as well as what the MSI ViewportOrigin was on that moment. Method AssociatedObject_ManipulationDelta then simply checks if the delta event sports a scaling in x or y direction – if it does, it calculates the properties for a new ‘logical point’ to be fed into the ZoomAboutLogicalPoint method of the MultiScaleImage. If there is no scaling, the user just panned, and a new ViewportOrigin is being calculated in the MSI’s own coordinate system which runs from 0,0 to 1,1. And that’s all there is to it.

If you download my sample mapviewer application it’s actually quite simple to test drive this

  • Add a Windows Phone 7 class library LocalJoost.Behaviours to the projects
  • Reference this project from WP7viewer
  • Create the behaviour described above
  • Open MainPage.xaml in WP7Viewer
  • Find the MultiScaleImage called “msi” and remove all bindings except MapTileSource, so that only this remains:
<MultiScaleImage x:Name="msi" 
   MapMvvm:BindingHelpers.MapTileSource="{Binding CurrentTileSource.TileSource}">
</MultiScaleImage>
  • Add the behaviour to the MultiScaleImage using Blend or follow the manual procedure below:
  • Declare the namespace and the assembly in the phone:PhoneApplicationPage tag like this
xmlns:LJBehaviours="clr-namespace:LocalJoost.Behaviours;assembly=LocalJoost.Behaviours"
  • Add the behaviour to the MSI like this
<MultiScaleImage x:Name="msi" 
   MapMvvm:BindingHelpers.MapTileSource="{Binding CurrentTileSource.TileSource}">
  <i:Interaction.Behaviors>
      <LJBehaviours:PanZoomBehaviour/>
  </i:Interaction.Behaviors>
</MultiScaleImage>

And there you go. You can now zoom in and out using two or more fingers. That is, if you have a touch screen. If you don’t have a touch screen and you were not deemed important enough to be assigned a preview Windows Phone 7 device then you are in good company, for neither have I, and neither was I ;-). But fortunately there is Multi Touch Vista on CodePlex. It needs two mice (or more, but I don’t see how you can operate those), and it’s a bit cumbersome to set up, but at least I was able to test things properly. So, don’t let the lack of hardware deter you getting on the Windows Phone 7 bandwagon!

What I learned from this: behaviours will give an interesting twist to design decisions. When is it proper to solve things into behaviours, and when in a model by binding? For me, it’s clear that in this case the behaviour wins from the model – it’s far easier to make, understand and – above all – apply! For now, just drag and drop the behaviour on top of a MultiScaleImage and bang – zoom and pan. No complex binding expressions. 

Incidentally, although this behaviour was created with maps in mind, in can be applied to any MultiScaleImage of course, showing ‘ordinary’ image data.

For those who are not very fond of typing: the sample map application with the behaviour  already added and configured can be downloaded here. For those lucky b******s in possession of a real live device: you will find the XAP here. I would very much appreciate feedback on how the thing works in real life.

05 August 2010

Fixing CLSA property registration issues in child objects

AKA ‘avoiding the dreaded “Can not register property YourProperty after containing type (YourBaseType) has been instantiated” error message’

Somewhere between CSLA 3.0 en 3.6 a new way of registering properties has become into being:

// old skool CSLA
private string _oldProp = string.Empty;
public string OldProp
{
  get
  {return _oldProp;}	 
  set
  { if (value == null) value = string.Empty;
    if (!_oldProp.Equals(value))
    {
      _oldProp = value;
      PropertyHasChanged("OldProp");
    }
  }
}

//new skool CSLA
private static PropertyInfo NewPropProperty = 
  RegisterProperty(c => c.NewProp);
public string NewProp
{
	get { return GetProperty(NewPropProperty); }
	set { SetProperty(NewPropProperty, value); }
}

In CSLA 4.0 the last style is mandatory, so I started upgrading some objects (while currently using CSLA 3.8.3) in anticipation. So I upgraded my base object

using Csla;

namespace CslaInheritance
{
  public abstract class MyBaseClass : BusinessBase<MyBaseClass>
  {

    protected static PropertyInfo<string> MyProp1Property = 
        RegisterProperty<string>(c => c.MyProp1);
    public string MyProp1
    {
      get { return GetProperty(MyProp1Property); }
      set { SetProperty(MyProp1Property, value); }
    }

    protected static PropertyInfo<string> MyProp2Property = 
        RegisterProperty<string>(c => c.MyProp2);
    public string MyProp2
    {
      get { return GetProperty(MyProp2Property); }
      set { SetProperty(MyProp2Property, value); }
    }
  }
}
and then my child object
using Csla;

namespace CslaInheritance
{
  public abstract class MyConcreteClass1 : MyBaseClass
  {
    protected static PropertyInfo<string> ConcreteProp1Property = 
      RegisterProperty<string>(c => c.ConcreteProp1);
    public string ConcreteProp1
    {
      get { return GetProperty(ConcreteProp1Property); }
      set { SetProperty(ConcreteProp1Property, value); }
    }

    protected static PropertyInfo<string> ConcreteProp2Property =
      RegisterProperty<string>(c => c.ConcreteProp2);
    public string ConcreteProp2
    {
      get { return GetProperty(ConcreteProp2Property); }
      set { SetProperty(ConcreteProp2Property, value); }
    }
  }
}

And then I noticed something odd: according to the compiler, ConcreteProp1 and ConcreteProp2 were not defined. Even worse is the situation when you choose to upgrade your properties not using lambda expressions, but PropertyInfo objects, like this:

    protected static PropertyInfo<string> ConcreteProp3Property =
      new PropertyInfo<string>("ConcreteProp3Property");
    public string ConcreteProp3
    {
        get { return GetProperty(ConcreteProp3Property); }
        set { SetProperty(ConcreteProp3Property, value); }
    }
because this will compile - and run. Until you create a second child class MyConcreteClass2, instantiate it, then instantiate a MyConcreteClass1 – and then you will get a cryptical runtime error message saying “Can not register property ConcreteProp1Property after containing type MyBaseClass has been instantiated”.

Fortunately the CSLA framework comes with sources, and after some rooting around I found the culprit, if you can call it that, in Csla.BusinessBase:

protected static PropertyInfo<P> 
  RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)
{
  PropertyInfo reflectedPropertyInfo = 
    Reflect<T>.GetProperty(propertyLambdaExpression);

  return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(
    typeof(T), reflectedPropertyInfo.Name));
}

Although MyConcreteClass1 inherits from MyBaseClass, MyBaseClass inherits in turn from templated class BusinessBase<MyBaseClass>. Therefore, in RegisterProperty called from MyConcreteClass1 T is still MyBaseClass. It does not matter that I actually called it from a child class. So what happens is that all the statics are defined in the base class MyBaseClass. If you are using the lambda variant to register, the compiler saves your *ss, but if you use the PropertyInfo method something weird happens. Remember, statics in a class are initialized as soon as you touch any one of statics. So what happens is: you instantiate your concrete child class, immediately the statics of both the concrete and the base class are initialized, and all the properties are registered in the base class. If you try to instantiate a second concrete child class, Csla finds that your base class properties are already initialized, and the dreaded “Can not register property ConcreteProp1Property after containing type MyBaseClass has been instantiated” error message appears.

Now you can of course change the way you implement classes. I might make MyBaseClass generic as well, then T changes along. But when upgrading an existing API out of a situation in which direct inheritance used to be perfectly legal, it’s a different story.

There are actually two ways out of this. The first one is: use PropertyInfo, but explicitly name the object type to which the property belongs

protected static PropertyInfo<string> ConcreteProp3Property =
  RegisterProperty(typeof(MyConcreteClass1), 
  new PropertyInfo<string>("ConcreteProp3Property"));
public string ConcreteProp3
{
    get { return GetProperty(ConcreteProp3Property); }
    set { SetProperty(ConcreteProp3Property, value); }
}

This works, but I like the solution below better, because that uses lambda expressions again and so your friend the compiler ;-) can help you catch typo’s. The only way I see to realize that is to add a static method at the bottom of your class

private static PropertyInfo<T> RegisterPropertyLocal<T>(
  Expression<Func<MyConcreteClass1, object>> propertyLambdaExpression)
{
  var reflectedPropertyInfo = 
  Reflect<MyConcreteClass1>.GetProperty(propertyLambdaExpression);
  return RegisterProperty(typeof(MyConcreteClass1),
    Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<T>(
    typeof(MyConcreteClass1),
    reflectedPropertyInfo.Name);
}
and then register your properties like this from now on:
protected static PropertyInfo<string> ConcreteProp1Property = 
  RegisterPropertyLocal<string>(c => c.ConcreteProp1);
public string ConcreteProp1
{
  get { return GetProperty(ConcreteProp1Property); }
  set { SetProperty(ConcreteProp1Property, value); }
}

The drawback of this solution is, of course, that you have to define a static RegisterPropertyLocal in every inherited class you define. But at least you will be saved from typos and weird runtime errors.

Now you are ready to upgrade, but I would recommend recording some macros to do the actual syntax change, unless you are very fond of very dull repetitive typing jobs ;-)