Semantic Zoom (Universal Apps)

6 minute read

Hub App

This will be a bit of a deep dive into the Semantic Zoom control and it’s usage in a windows c# / xaml universal app project. Starting with something which I’m sure everyone is familiar with, that is, the visual studio navigation template which has some really nice features; such as the dummy data model which makes standing up user interface prototypes quick and easy. So, File > New Project and in the ensuing project template dialog navigate to Visual C# > Store Apps > Universal Apps > Hub App (Universal Apps) and spin up the project.

 

clip_image003

 

The universal project provides a Windows 8.1, a Windows Phone 8.1 and a shared project which houses source and assets to be linked into both Phone and Windows projects. More specifically the Hub app consists of a multi-page, hierarchical user experience built around the Hub Control backed by design-time and runtime data specified in JSON format. I’ll use the Semantic Zoom control to visualise the hierarchical data source across both the Windows and Windows Phone platforms. Here is the starting point for each platform:

 

clip_image006

 

Firstly, I’ll remove the Hub Control from both Windows Phone and Windows projects as I’m only interested in reusing the data model. I’m going to switch over to the Windows Phone project and work in that one before re-applying what I learn back to the Windows project.

 

CollectionViewSource

Whilst not a pre-requisite I am going to make use of the CollectionViewSource class to act as an intermediary between the data and the user interface. This has a number of advantages; it can serve to synchronise the concept of ‘current’ item between multiple bindings to the user interface and also it can be used to communicate that the data is ‘grouped’ so that the user interface element knows how to interface with it.

The following xaml goes into the ResourceDictionary and

 

  1. <CollectionViewSource x:Name="groupViewSource"
  2.                       Source="{Binding Groups}"
  3.                       IsSourceGrouped="True"
  4.                       ItemsPath="Items"
  5.                       d:Source="{Binding Groups, Source={d:DesignData Source=../SemanticZoomTest.Shared/DataModel/SampleData.json, Type=data:SampleDataSource}}" />

A namespace import is also required for the design-time properties

 

xmlns:d=http://schemas.microsoft.com/expression/blend/2008

 

Notice that the CollectionViewSource itself is bound to the Groups property of the current DataContext (the DataContext is bound to the DefaultViewModel property which is exposed by the code-behind HubPage.xaml.cs file).

I have used the properties on the CollectionViewSource to describe the layout of my data source, i.e. IsSourceGrouped and ItemsPath, this helps the target of the Databinding we will subsequently set up to understand the ‘shape’ of the data. Also, note that the design time data source points directly to the json data file which is also where the runtime data is parsed from.

 

Views

So with those preliminaries over time to set up the actual user interface elements. So start with the SemanticZoom control for which you need to define content for both zoomed in view and zoomed out view as shown below:

 

  1. <SemanticZoom x:Name="MySemanticZoom">
  2.     <SemanticZoom.ZoomedInView>
  3.         // Zoomed in ui
  4.     </SemanticZoom.ZoomedInView>
  5.     <SemanticZoom.ZoomedOutView>
  6.         // Zoomed out ui
  7.     </SemanticZoom.ZoomedOutView>
  8. </SemanticZoom>

 

 

 

 

 

This should be inserted into the LayoutRoot Grid.

Adding a ListView into the xaml to define the content for the zoomed in view:

 

  1. <ListView ItemsSource="{Binding Source={StaticResource groupViewSource}}"
  2.           ItemTemplate="{StaticResource MyListViewTemplate}">
  3.     <ListView.GroupStyle>
  4.         <GroupStyle HidesIfEmpty="False">
  5.             <GroupStyle.HeaderTemplate>
  6.                 <DataTemplate>
  7.                     <TextBlock Text="{Binding Title}"
  8.                                Style="{ThemeResource HeaderTextBlockStyle}"></TextBlock>
  9.                 </DataTemplate>
  10.             </GroupStyle.HeaderTemplate>
  11.         </GroupStyle>
  12.     </ListView.GroupStyle>
  13. </ListView>

 

 

 

 

 

 

 

 

Notice that this binds to the CollectionViewSource we defined earlier and since the CollectionViewSource is defined as being grouped we need to supply a DataTemplate to define how the group headers are displayed.

And for the zoomed out view:

 

  1. <SemanticZoom.ZoomedOutView>
  2.     <GridView ItemsSource="{Binding Source={StaticResource groupViewSource}, Path=CollectionGroups}"
  3.               ItemTemplate="{StaticResource MyGridViewItemTemplate}"
  4.               Background="Gray">
  5.     </GridView>

 

 

 

 

Note that the GridView binds its ItemsSource to the CollectionGroups property of the CollectionViewSource.

 

clip_image008

 

Now, if you are accustomed to using Semantic Zoom on windows 8 then you’ll know that to switch from zoomed in to zoomed out you can either pinch-zoom or tap the supplied ‘-’ and ‘+’ buttons. These are missing from the standard Semantic Zoom template on windows phone 8.1 but clicking the group headers in the zoomed in view and the items in the zoomed out view provides the same result.

Ok, so it’s time to run it up in the emulator and give it a try out.

 

clip_image010

 

Tapping the one of the group headers takes you to the zoomed out view then selecting a group from there jumps you back to the right spot in the zoomed in view.

Ok, that works well enough so as an experiment I’m going to share the HubPage between the Windows Phone and Windows projects by dragging it into the Shared project and deleting it from the individual projects. The styles defined in the templates do not match across the platforms as you would expect and ordinarily I would take the time to define my styles for each platform correctly. As it is I will just choose styles which already exist on both.

Also, the Hub only supports Portrait orientation on the phone so the compiler’s help is needed in the HubPage constructor as below:

 

  1. #if WINDOWS_PHONE_APP
  2.             // Hub is only supported in Portrait orientation
  3.             DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait;
  4. #endif

 

 

 

With that done we can run each project and compare the results:

Here’s the same thing running in the Windows 8 Simulator:  

 

clip_image012

 

Note that there are some differences between the Windows 8 and Windows Phone representations; the former supports pinch to zoom and has zoom in and zoom out buttons while the latter does not. Please find a sample solution here http://1drv.ms/1hvqwgJ .

 

ISemanticZoomInformation

ISemanticZoomInformation is the interface used by the SemanticZoom control to get its work done and is implemented out-of-the-box by GridView and ListView . So by sub-classing a UI element and having the sub-class implement ISemanticZoomInformation allows it to be used inside a SemanticZoom control. I was recently asked about Semantic Zoom using other controls; specifically a FlipView, which can be realised on Windows by sub-classing FlipView and having the subclass implement ISemanticZoomInformation.

However, trying this on Windows Phone doesn’t work and examination of the control templates sheds some light on the reason and the differences. The built-in control templates can be found at <Program Files>\Windows Phone Kits\8.1\Include\abi\Xaml\Design and <Program Files >\Windows Kits\8.1\Include\winrt\xaml\design\generic.xaml for Windows Phone and Windows respectively. (Note that editing the control templates in Blend or Visual Studio does not give the option to create a new one by first copying the existing one). The Windows version implements its template with a ScrollViewer whilst the Phone version uses a Popup.

So, back to the original question; how to implement on Windows Phone? Well, to achieve Semantic Zoom with the FlipView it is possible to use the Windows control template with the Windows Phone control however it is not a straight swap as there are scaling and zooming differences brought about by using the different templates. It is possible to get something workable by altering the RenderTransformOrigin values for some elements in the template and whilst I’m not suggesting that the full semantic zoom experience should be the same cross-platform I think some aspects of it work in some scenarios.

Please find a sample illustrating this here http://1drv.ms/1hvqwgJ .

 

Conclusion

It’s interesting to consider the user experience of particular controls as they span across different form factors particularly as Universal apps now facilitate sharing across a whole range of screen sizes, shapes and densities now. Whilst maximising the experience across those form factors it’s important that the platform allows developers to fully customise those experiences whilst operating within broad user interface guidelines.

Comments