Archive for December, 2011

Windows Phone – Reactive Extensions (Rx)

In my previous post I talked about how important it is to use page transitions and animations in your application to increase the overall user experience. Wouldn’t it be nice if we could extend this experience a bit, and take it to the next level of user feedback and interaction.

Fortunately there is a framework called Reactive Extensions (Rx) that enables us to do all kinds of super cool stuff in our applications.

This post will show how easy it is to use the Reactive Extensions framework to increase the user experience when loading data from services and showing it to the user in a more elegant way.

Reactive Extensions (Rx)

First of all, Reactive Extensions is a library to compose asynchronous and event-based programs using observable collections and LINQ-style query operators. You can start learning about Rx at MSDN if this is new to you: http://msdn.microsoft.com/en-us/data/gg577609

In the sample project that I’m going to build, I will simulate a call to a web service to fetch data, and when data is returned I will populate a ListBox with the data. The items will be added one by one to the list with a nice subtle animations to give feedback to the user that items are being added to the list. I will simulate fetching from different services and add them result items to the list as soon as they arrive.

1. Create the Phone project

You start by creating a Windows Phone 7.1 project using the “Windows Phone Databound Application” template.

This will give you all the needed UI automatically, we will just refactor it and change so that it uses loading animations and Reactive Extensions when displaying the items to the user.

2. Change the UI

Now let’s change the Item Template for the ListBox so that each row has a solid background color (will be easier to see the animation) and finally add an animation/storyboard that is executed when a row is loaded (using event trigger).

The final ItemTemplate:

    <DataTemplate>
        <Grid x:Name="TileGrid">
            <Grid.Triggers>
                <EventTrigger RoutedEvent="Grid.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation 
                                Storyboard.TargetName="TileGrid"
                                Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
                                Duration="0:0:0.5" To="0" />
                            <DoubleAnimation
                                Storyboard.TargetName="TileGrid"
                                Storyboard.TargetProperty="Opacity"
                                Duration="0:0:0.5" To="1" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Grid.Triggers>
            <StackPanel Margin="0,0,0,17" Width="432" Height="78" Background="{StaticResource PhoneAccentBrush}">
                <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
            <Grid.Projection>
                <PlaneProjection CenterOfRotationX="0" CenterOfRotationY="0"
                        RotationY="-90" />
            </Grid.Projection>
        </Grid>
    </DataTemplate>

If we run the application now, we already see an animation for the loaded event.

But all items are loaded at the same time. What if we wanted each row to be loaded one by one with a 200 millisecond delay? How would we do that?
One option is to use a background worker that has a 200 millisecond sleep in each loop that adds an item to the Items collection that is used as ItemsSource on the ListBox.
Let’s try that and see how it would look like and then later simplify the source code using Reactive Extensions.

3. Add item loaded delays
Start by refactoring the MainViewModel.cs LoadData() method to hold the sample data in a temporary list (so that we can use that list in our background worker to finally add them one by one to the Items collection)
Hint: to change the source code on multiple rows at the same time, you can hold down the Alt key while highlighting text in the editor to select parts of the text on multiple rows and then type on your keyboard to change the text on multiple rows at the same time. Realy nice feature :)

The final source code with BackgroundWorker:

    public void LoadData()
    {
        // Temporary hold the items in memory
        ObservableCollection<ItemViewModel> items = new ObservableCollection<ItemViewModel>();

        // Sample data; replace with real data
        items.Add(new ItemViewModel() { LineOne = "runtime one", ... });
        items.Add(new ItemViewModel() { LineOne = "runtime two", ... });
        items.Add(new ItemViewModel() { LineOne = "runtime three", ... });
        ...
        items.Add(new ItemViewModel() { LineOne = "runtime sixteen", ... });

        this.IsDataLoaded = true;

        // Create background worker that adds all items to the Items collection with delays
        var worker = new BackgroundWorker();
        worker.DoWork += delegate(object sender, DoWorkEventArgs args)
        {
            // Loop through all the items
            for (int i = 0; i < items.Count - 1; i++)
            {
                // Create a slight delay and add each item to the Items collection
                Thread.Sleep(200);
                Deployment.Current.Dispatcher.BeginInvoke(
                    () =>
                    {
                        Items.Add(items[i]);
                    });
            }
        };
        worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs args)
        {
        };
        worker.RunWorkerAsync();
    }

If we run the application now we have a nice animation for each row when they are added to the Items collection

4. Add Reactive Extensions (Rx)
So the above use of background worker is working just fine, but can we simplify the source code using Rx?
First of all to use Rx you need to add the following references to the project

  • Microsoft.Phone.Reactive
  • System.Observable

and the following using statements

    using Microsoft.Phone.Reactive;
    using System.Linq;

Then finally remove the Background Worker code section and replace with the following code and also add the method AddItem

    public void LoadData()
    {
    
    ....

    // Convert the result to an Observable sequence
    items.ToObservable()
        // Add selector method that selects each item with 200 ms delay
        .Zip(Observable.Interval(TimeSpan.FromMilliseconds(200)), (d, t) => d)
        // asyncrounously notify observers using the current dispatcher
        .ObserveOnDispatcher()
        // subscribe a value handler to an observable sequence
        .Subscribe(AddItem); 
    }

    private void AddItem(ItemViewModel item)
    {
        Items.Add(item);
    }

If we run the application now we have the same result as expected. Although the source code is now a lot nicer, and we don’t have to worry about cross thread issues, index out of bound when looping through the items etc. This is just a really simple useage of Rx framework, but there is a lot more cool stuff you can do with it. Perhaps I’ll write a post later on a more complicated scenario.

Performance

You should always pay attention to performance on the phone when using animations and transitions. If we enable draw regions we can see that during loading the list box items are redrawn several times, although this is OK in this simple application but something to pay attention to.

    // Show the areas of the app that are being redrawn in each frame.
    Application.Current.Host.Settings.EnableRedrawRegions = true;

Happy Coding!

Advertisements

Windows Phone – Animations and Transitions

Microsoft is introducing a fresh approach on UI design and user experiences based on the Metro design language and principles. Even though you follow the Metro design guidelines you are according to me only half-way there to a perfect design and user experience. If you think about all the out of the box experiences on the phone you realize that they feel a lot more alive than most of the apps you download from the marketplace. How is that? The simple answer is user experience through transitions and animations. Animations and transitions on the Windows Phone platform are fundamental elements that are deeply rooted in the UI concept.

Animations and Transitions

Animations is probably one of the most important features of Windows Phone. Most developers and customers I have talked to in the past tend to see animations as something extra fancy that you don’t need in an application, especially not in a LOB (line of business) application. I would argue and say that they are as important in a LOB app as in any other app.

Animations and transitions extends the user experience by giving subtle feedback to the user on what is going on, what is happening and to what is about to happen. It increases the overall experience.

A lot of applications are really static, no specific feedback to the user for any actions they perform, transition between pages and so on. The apps would feel much more polished and alive if the designers would spend time on creating subtle proper animations and transitions.

The Silverlight toolkit makes page transitions and user feedback super easy to implement. But be careful, overdoing animations will only annoy the users and detract the user experience.

Let’s go through how simple it is to add page transitions to your application.

  • First of all you need to install the Windows Phone Toolkit
  • add a reference to Microsoft.Phone.Controls.Toolkit to your project
  • in App.xaml.cs locate the InitializePhoneApplication method and change the RootFrame from a regular PhoneApplicationFrame to a TransitionFrame
        RootFrame = new Microsoft.Phone.Controls.TransitionFrame();
    
  • you have now prepared your application to use any of the page transitions provided by the toolkit.
  • finally add a page transition to your page. Either add xaml code to each page (which eventually leads to a lot of copy-paste) or create a Style that you reference in each page.

Xaml in each page

Start by creating a name space to the Windows Phone Toolkit

xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

add the following xaml to the page. This example uses the Turnstile transition. A good sample application that shows all the different page transitions is found at codeplex: http://pagetransitions.codeplex.com/

<phone:PhoneApplicationPage
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
… >
    <toolkit:TransitionService.NavigationInTransition>
        <toolkit:NavigationInTransition>
            <toolkit:NavigationInTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardIn"/>
            </toolkit:NavigationInTransition.Backward>
            <toolkit:NavigationInTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardIn"/>
            </toolkit:NavigationInTransition.Forward>
        </toolkit:NavigationInTransition>
    </toolkit:TransitionService.NavigationInTransition>
    <toolkit:TransitionService.NavigationOutTransition>
        <toolkit:NavigationOutTransition>
            <toolkit:NavigationOutTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardOut"/>
            </toolkit:NavigationOutTransition.Backward>
            <toolkit:NavigationOutTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardOut"/>
            </toolkit:NavigationOutTransition.Forward>
        </toolkit:NavigationOutTransition>
    </toolkit:TransitionService.NavigationOutTransition>

Better approach with Styles

To make the transitions easier to maintain, and easier to switch between different page transitions when trying out your application, I would suggest you to create a style resource for each different page transition you want to use.

    <!--Application Resources-->
    <Application.Resources>
        <Style x:Key="TurnstilePage" TargetType="phone:PhoneApplicationPage">
            <Setter Property="toolkit:TransitionService.NavigationInTransition">
                <Setter.Value>
                    <toolkit:NavigationInTransition>
                        <toolkit:NavigationInTransition.Backward>
                            <toolkit:TurnstileTransition Mode="BackwardIn"/>
                        </toolkit:NavigationInTransition.Backward>
                        <toolkit:NavigationInTransition.Forward>
                            <toolkit:TurnstileTransition Mode="ForwardIn"/>
                        </toolkit:NavigationInTransition.Forward>
                    </toolkit:NavigationInTransition>
                </Setter.Value>
            </Setter>
            <Setter Property="toolkit:TransitionService.NavigationOutTransition">
                <Setter.Value>
                    <toolkit:NavigationOutTransition>
                        <toolkit:NavigationOutTransition.Backward>
                            <toolkit:TurnstileTransition Mode="BackwardOut"/>
                        </toolkit:NavigationOutTransition.Backward>
                        <toolkit:NavigationOutTransition.Forward>
                            <toolkit:TurnstileTransition Mode="ForwardOut"/>
                        </toolkit:NavigationOutTransition.Forward>
                    </toolkit:NavigationOutTransition>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>

Then in each page where you want to use a page transition (note that we could omit x:Key to make this an implicit style and default for all pages) you simply reference the wanted page style in the following way

<phone:PhoneApplicationPage Style="{StaticResource TurnstilePage}" ... >

Enhance user actions with visual feedback

It’s also a good practice to add feedback to the user when he or she presses a button or selects an item in a list that performs an action. This can easily be done by using the Tilt Effect.

Conclusions

Adding page transitions to your app is really simple and increases the user experience a lot, but as noted before, be careful, overdoing animations and transitions will make your app annoying and potentially get really bad ratings.

Happy Coding!

%d bloggers like this: