XAML Playground
about XAML and other Amenities

Metro: Implement a parallactic scrolling for your GridView

2012-05-19T00:56:36+01:00 by codeblock

A customer of mine asked me about how to create a "parallactic scrolling" for the background of a GridView. For people that do not know what it is, parallactic scrolling is when you have a background image scrolling slower than the foreground content. This tecnique is mostly used in games to give the impression of depth of field with the overlapping of a number of elements that moves slower when they apper to be far from the observer.

To have a good example of this beautiful effect you can try the music hub of your Windows Phone. The Panorama based scrolling, when coupled with a background image, automatically apply a parallactic effect when you move from a panel to the following.

Coming to Windows 8, there are some application installed by default that shows a similar effect. Weather and Finacial apps shows a partial parallactic effect when transitionig between the start screen and the right content. GridView, ScrollViewer and other controls does not automatically apply this effect (almost not in windows 8 CP), but a simple trick let you easily show the effect in your apps.

First of all you have to produce an element, that is greater than the viewport in the direction you desire your scrolling to work. In the application of my user group it is an image made of people an the total size is almost double of the medium size of a screen device. This image is aligned to left and goes out of the screen on the right. Here is the code:

   1: <Grid>
   2:     <Image x:Name="backImage" Margin="0,0,0,30" 
   3:             HorizontalAlignment="Left" VerticalAlignment="Bottom" 
   4:             Source="/Assets/parallax_people.png" Width="2250" Height="200" Opacity="0.5" />
   5:  
   6:     <ScrollViewer x:Name="hScroll" 
   7:                   Style="{StaticResource HorizontalScrollViewerStyle}" Margin="0">
   8:         <!-- insert your content here -->
   9:     </ScrollViewer>
  10: </Grid>

The trick I'm showing works only with ScrollViewer because it requires to handle the ViewChanged event, but you can for sure include a GridView into a ScrollViewer and have the effect enabled for the control. And obviously this also apply to ListView as well.

Now, going to codebehind is is required to subscribe the ViewChanged event. This event is raised every time the user scrolls the content. So I have to recalculate the offset of the background using the HorizontalOffset property and to map the value to the total width of the image. Here is the code:

   1: private void hScroll_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
   2: {
   3:     var delta = (this.hScroll.HorizontalOffset / this.hScroll.ScrollableWidth) * (backImage.ActualWidth - this.hScroll.ViewportWidth);
   4:     this.backImage.Margin = new Thickness(-delta, 0, 0, 30);
   5: }

Once you have connected the method to the View the trick is done. In this code I use the Margin property to move the image. At the first sight you would have used a TranslationTranform. Unfortunately the Render tranforms clips the image so I finally adopted the Margin property with a negative value.

In my example you can tune the speed of the content  varying the width of the background image, but nothing else is required.

Metro: A simple class to handle retry on network calls

2012-05-18T00:31:23+01:00 by codeblock

After you start working with metro-style applications, you may be concerned by the extensively adopted asyncronous model. If you ever used Silverlight you can be aware that this model comes directly as an inheritance from it. In metro-style applications this model is taken to the extreme consequences. As an example WinRT exposes all the operations that takes longer than 50ms with an asyncronous pattern. But the most frequent case where you meet asynchronicity, is when you call the network.

The use of Task Parallel Library offers anumber of interesting opportunities to handle asynchronous operations and the benefits can make your code most simple and reusable. Recently I've created an interesting class (I called it NetworkCallManager). This class wraps every network call and let you control the flow of a call in the case it returns an error. It is common to handle timeouts, authentication issues and poor network connectivity and if you read the guidelines you know that they suggests you to let the user retry the failed operation. Here is the code I wrote:

   1: public class NetworkCallManager
   2: {
   3:     public event EventHandler<NetworkErrorEventArgs> NetworkError;
   4:  
   5:     protected virtual void OnNetworkError(NetworkErrorEventArgs args)
   6:     {
   7:         EventHandler<NetworkErrorEventArgs> handler = this.NetworkError;
   8:  
   9:         if (handler != null)
  10:             handler(this, args);
  11:     }
  12:  
  13:     public async Task<T> Execute<T>(Func<Task<T>> task)
  14:     {
  15:         bool retry = false;
  16:  
  17:         do
  18:         {
  19:             Exception error = null;
  20:  
  21:             try
  22:             {
  23:                 return await task();
  24:             }
  25:             catch (Exception ex)
  26:             {
  27:                 error = ex;
  28:             }
  29:  
  30:             if (error != null)
  31:             {
  32:                 NetworkErrorEventArgs args = new NetworkErrorEventArgs(error);
  33:                 this.OnNetworkError(args);
  34:                 retry = !args.Cancel;
  35:             }
  36:  
  37:         } while (retry);
  38:  
  39:         throw new NetworkOperationCancelledException("Network operation has been cancelled");
  40:     }
  41: }

The main method, responsible to place the network call, is named Execute. It receives a Task<T> where T is compatible with the return type of the network call we have to execute. The important thing to understand is that you have tu use a lambda expression because the code inside the method can recall this function lot of times. The method works as a pass-through function since it returns the same type as the function passed. So when the task is completed you can get directly the result.

Inside the body the method starts a loop where it runs the task and handles exceptions. When an exception is raised it gracefully handle the error and notifies it to the caller. The user can choose to break the operation or to retry. Here is how you can use the class:

   1: // omissis
   2:  
   3: NetworkCallManager ncm = new NetworkCallManager();
   4: ncm.NetworkError += HandleNetworkError;
   5:  
   6: try
   7: {
   8:     this.Speeches = await ncm.Execute<IEnumerable<SpeechDTO>>(() => this.DataService.GetSpeechesInYears(5));
   9: }
  10: catch (NetworkOperationCancelledException ex)
  11: {
  12:     // swallow
  13: }
  14: catch (Exception ex)
  15: {
  16:     this.DialogService.ShowGenericError(ex.Message);
  17: }
  18: finally
  19: {
  20:     ncm.NetworkError -= HandleNetworkError;
  21: }
  22:  
  23: private async void HandleNetworkError(object sender, NetworkErrorEventArgs e)
  24: {
  25:     e.Cancel = await this.DialogService.ShowNetworkError(e.Error);
  26: }
  27:  
  28: // omissis

This pattern let you to use the wrapper in a trasparent way and directy get the result. It also raises a specific exception when the user choose to stop the operation instead of retry. To me this spered me to implemend this flow directly into the page.

Implement a NavigationService for MVVM in Metro Applications

2012-05-10T00:37:56+01:00 by codeblock

When you write a Metro-style app using the MVVM pattern, you are requested to abstract navigation for the pattern purposes. The problem comes from having navigation methods (Navigate, GoBack, etc...) available only in the View via the Frame control and navigate from the ViewModel may be an hard task.

During the development of my last metro app for my user group, I found a stylish way of creating a NavigationService to be injected in ViewModels. The trick is to create a NavigationService class and let it create and initialize the RootFrame and inject it into the Window.Current.Content.

   1: public class NavigationService : INavigationService
   2: {
   3:     protected Frame RootFrame { get; private set; }
   4:  
   5:     public NavigationService()
   6:     {
   7:         this.RootFrame = new Frame();
   8:     }
   9:  
  10:     public void Initialize(Window window, bool activate = true)
  11:     {
  12:         if (window.Content == null)
  13:             window.Content = this.RootFrame;
  14:  
  15:         if (activate)
  16:             window.Activate();
  17:     }
  18:  
  19:     public virtual void Navigate(Type destination, object parameter = null)
  20:     {
  21:         // avoid navigation if current equals to destination
  22:  
  23:         if (this.RootFrame.CurrentSourcePageType != destination)
  24:             this.RootFrame.Navigate(pageType, parameter);
  25:     }
  26:  
  27:     public virtual void GoBack()
  28:     {
  29:         if (this.RootFrame.CanGoBack)
  30:             this.RootFrame.GoBack();
  31:     }
  32:     
  33:     public virtual void GoForward()
  34:     {
  35:         if (this.RootFrame.CanGoForward)
  36:             this.RootFrame.GoForward();
  37:     }
  38:     
  39:     public virtual bool CanGoBack
  40:     {
  41:         get { return this.RootFrame.CanGoBack; }
  42:     }
  43:     
  44:     public virtual bool CanGoForward
  45:     {
  46:         get { return this.RootFrame.CanGoForward; }
  47:     }
  48:     
  49:     public virtual void Save()
  50:     {
  51:         throw new NotImplementedException();
  52:     }
  53:     
  54:     public virtual void Load()
  55:     {
  56:         throw new NotImplementedException();
  57:     } 
  58: }

The previous box shows the code of my service: first of all the service implements an interface. This serves for the dependency injection since ViewModel only accept INavigationService to make it testable. The Initialize method sets the Window.Content to the frame instance I created in the constructor. Finally the class implements all the required navigation methods. Interesting to say, you can implement Save and Load using Framee.GetNavigationStatus and Frame.SetNavigationStatus to persist the navigation backstack when your app is terminated. Here is how to use the class in the App.xaml.cs:

   1: protected override void OnLaunched(LaunchActivatedEventArgs args)
   2: {
   3:     // get the instance from Injection Container
   4:     INavigationService ns = this.Container.Resolve<INavigationService>();
   5:  
   6:     if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
   7:     {
   8:         // load state if app was terminated
   9:         ns.Load();
  10:     }
  11:     
  12:     // initialize current window
  13:     ns.Initialize(Window.Current);
  14:  
  15:     // navigate to the first page
  16:     ns.Navigate(Pages.MainPageType);
  17: }
  18:  
  19: private void OnSuspending(object sender, SuspendingEventArgs e)
  20: {
  21:     // get the instance from Injection Container
  22:     INavigationService ns = this.Container.Resolve<INavigationService>();
  23:  
  24:     // save navigation status
  25:     ns.Save();
  26: }

This code shows also how to load and save to persistence media the navigation history. In this way when you return to the app after it has been terminated, it can reload again an exact navigation.