DotNetCurry Logo

Windows 8: Working with Semantic Zoom using C# and XAML

Posted by: Mahesh Sabnis , on 2/13/2013, in Category Windows Store Apps
Views: 26643
Abstract: The SemanticZoom control is a Modern way to display hierarchical or groups of data in Windows 8 Store Apps. It helps represent large set of the data intuitively, and that can be navigated easily on small touch devices like tablets or on traditional desktop apps. This article explores this control.

Windows 8 is an excellent platform for designing and developing rich interactive applications using Store Apps Application Model. These applications can be developed using XAML with C#, HTML5 with JavaScript and C++ also. These apps target audiences who want to make use of devices like tablets for a live connection with their working locations over internet. There are several features offered by Windows Store apps which makes use OS interfaces like Share, Search, and FilePicker etc.

If you want to build a Windows Store App for the Line-Of-Business (LOB) functionality, as a developer, you need to visualize the end user needs and adapt the controls and framework at hand to fulfill real requirement.

 

A Use Case

Consider a scenario where you are developing an application for a doctor or any other professional who potentially works with multiple clients and needs Task Management software.

In case of a doctor, let us assume that they are specialty consultants who visit various hospitals in the area. In each hospital, they have patients to diagnose. If they carry a tablet with them that has an app to manage the patient appointments, it gives them a heads up on the tasks at hand. This is an ideal scenario for developing LOB application with possible extensions to Hospital backend system to download Appointments directly.

For a two (or multi) level view, traditionally we’ve used a hierarchical UI representation like a tree. But instead of a Tree, in Modern apps we have a control call the Semantic Zoom. This control can be configured to show High Level data and then can be drilled (zoomed in) down to see detailed data. For example in the image shown below, we see an initial Zoomed Out view of the Hospital where the doctor has to visit.

image

When the user taps on a Hospital, they are zoomed into the Patient list as show in the next figure.

image

This functionality is implemented via the Semantic Zoom Control that we will explore in detail today.

The Semantic Zoom Control

This is a touch optimized control used in Windows Store Apps on Windows 8. The major advantage of this control is that by using it, large set of the data can be very easily displayed.

For organizing and presenting data, this control uses zoom levels i.e. ZoomedInView and ZoomedOutView. The ZoomInView shows the data in details whereas ZoomedOutView shows data in group. This enables end-user to quickly view and interact with the data. The end-user can interact with control using Mouse Scroll and the Control button or the Ctrl with + key and Ctrl with – key for ZoomedInView and ZoomedOutView respectively. In touch devices, they can tap to zoom and multi-finger ‘pinch’ to zoom out.

Let’s build the sample now.

Step 1: Open VS 2012 and create a new Windows Store App project, name it as ‘Store_CS_UsingSemanticZoom’. In this project, add a new Class file and name it as DataClass.cs. Add the following code in it:

using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Store_CS_UsingSemanticZoom
{
/// <summary>
/// Class for Patients Info
/// </summary>
public class PatientInfo
{
  public int PatientId { get; set; }
  public string PatientName { get; set; }
  public int Age { get; set; }
  public string HospitalName { get; set; }
}
/// <summary>
/// Class to Store Patients per Hospital
/// </summary>
public class HospitalGroup
{
  public string HospitalName { get; set; }
  public List<PatientInfo> Patients { get; set; }
}

/// <summary>
/// Data Access class where the Patient Information is stored.
/// </summary>
public class DataAccess
{
  ObservableCollection<PatientInfo> _Patients;
  public ObservableCollection<PatientInfo> Patients
  {
   get { return _Patients; }
   set { _Patients = value; }
  }
  public DataAccess()
  {
   Patients = new ObservableCollection<PatientInfo>();
   Patients.Add(new PatientInfo() { PatientId = 1, PatientName = "Ajay", Age = 30, HospitalName = "JD Med-Institute"});
   Patients.Add(new PatientInfo() { PatientId = 2, PatientName = "Rajesh", Age = 28, HospitalName = "JD Med-Institute" });
   Patients.Add(new PatientInfo() { PatientId = 3, PatientName = "Sanjay", Age = 17, HospitalName = "JD Med-Institute" });
   Patients.Add(new PatientInfo() { PatientId = 4, PatientName = "Gopal", Age = 19, HospitalName = "City Hospital"});
   Patients.Add(new PatientInfo() { PatientId = 5, PatientName = "Ram", Age = 45, HospitalName = "City Hospital" });
   ...
  }

  public ObservableCollection<PatientInfo> GetPatients()
  {
   return Patients;
  }
}
}

This is our dummy Data Source. Ideally this data will come from a service to which the system will connect when the network is available.

Step 2: Open MainPage.xaml and add the following XAML code in the Page Resources:

<Page.Resources>
<!--Style for Displaying the Patient Record Style-->
<Style x:Key="PatientRecordStyle" TargetType="TextBlock">
  <Setter Property="FontFamily" Value="Segoe UI Light"/>
  <Setter Property="FontSize" Value="18"/>
  <Setter Property="Width" Value="150"></Setter>
  <Setter Property="Foreground" Value="Red"></Setter>
</Style>
<!--Ends Here-->

<!--Style for the Labels for the Patient e.g. ID, Name, Age etc.-->
<Style x:Key="PatientDetailsStyle" TargetType="TextBlock">
  <Setter Property="FontFamily" Value="Segoe UI Light"/>
  <Setter Property="FontSize" Value="18"/>
  <Setter Property="Width" Value="150"></Setter>
  <Setter Property="Foreground" Value="Black"></Setter>
</Style>
<!--Ends Here-->

       
<!--DataTemplate to Display Patient Details-->
<DataTemplate x:Key="PatientInfoTemplate">
  <StackPanel Orientation="Horizontal">
   <StackPanel Margin="0,0,0,0" Orientation="Vertical">
    <Grid>
     <Grid.RowDefinitions>
      <RowDefinition Height="30"></RowDefinition>
      <RowDefinition Height="30"></RowDefinition>
      <RowDefinition Height="30"></RowDefinition>
     </Grid.RowDefinitions>
     <Grid.ColumnDefinitions>
      <ColumnDefinition Width="80"></ColumnDefinition>
      <ColumnDefinition Width="80"></ColumnDefinition>
      </Grid.ColumnDefinitions>
      <TextBlock Text="ID" Grid.Row="0" Grid.Column="0" Style="{StaticResource PatientDetailsStyle}"></TextBlock>
      <TextBlock TextWrapping="NoWrap"  Text="{Binding PatientId}" Grid.Row="0" Grid.Column="1"  Style="{StaticResource PatientRecordStyle}"/>
      <TextBlock Text="Name" Grid.Row="1" Grid.Column="0" Style="{StaticResource PatientDetailsStyle}"></TextBlock>
      <TextBlock TextWrapping="NoWrap"  Text="{Binding PatientName}" Grid.Row="1" Grid.Column="1"  Style="{StaticResource PatientRecordStyle}"/>
      <TextBlock Text="Age" Grid.Row="2" Grid.Column="0" Style="{StaticResource PatientDetailsStyle}"></TextBlock>
      <TextBlock TextWrapping="NoWrap"  Text="{Binding Age}" Grid.Row="2" Grid.Column="1" Style="{StaticResource PatientRecordStyle}"/>
     </Grid>
    </StackPanel>
   </StackPanel>
  </DataTemplate>
       
  <ItemsPanelTemplate x:Key="GridViewItemsWisePanel">
   <StackPanel Orientation="Horizontal" />
  </ItemsPanelTemplate>
  <!--DataTemplate for the Hospital Name Group-->
  <DataTemplate x:Key="PatientInfoZoomedOutTemplate">
   <Border BorderBrush="Red" BorderThickness="2" Margin="10" Padding="10">
    <TextBlock Text="{Binding Group.HospitalName}" FontFamily="Segoe UI Light" FontSize="15" Foreground="Red"  FontWeight="ExtraBold"/>
   </Border>
  </DataTemplate>
 
  <!--The CollectionViewSource. This contains the Patients information-->
  <CollectionViewSource x:Name="PatientsCollection"  IsSourceGrouped="True" ItemsPath="Patients"></CollectionViewSource>
  <!--Ends Here-->
</Page.Resources>

There are three templates and one CollectionViewSource defined in the resources. The template PatientInfoTemplate is used to display the patient information in the ZoomedInView. Similarly the template PatientZoomedOutTemplate is used to display the Hospital Name group. With the templates defined, let’s use them in the control.

Step 3: Add the following XAML for the SemanticZoom control:

<!--The Semantic Zoom Control Where Patients Information is shown-->
<SemanticZoom x:Name="PatientInfoZoomControl"  Margin="10,30,0,0"
Width="600" Height="500"
Grid.Row="1" Background="Beige">
     
<SemanticZoom.ZoomedOutView>
  <GridView x:Name="ZoomedOutPatGridView"
            MinWidth="390" MinHeight="200"
            ItemTemplate="{StaticResource PatientInfoZoomedOutTemplate}"
            BorderBrush="Yellow" BorderThickness="2"
            ScrollViewer.VerticalScrollBarVisibility="Visible"
            ScrollViewer.HorizontalScrollBarVisibility="Visible"
            SelectionMode="None" MaxWidth="1000" >
   <GridView.ItemsPanel>
    <ItemsPanelTemplate>
     <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Stretch" Width="200" />
    </ItemsPanelTemplate>
   </GridView.ItemsPanel>
  </GridView>
</SemanticZoom.ZoomedOutView>
           
<SemanticZoom.ZoomedInView>
  <GridView x:Name="ZoomedInPatGridView"
      HorizontalAlignment="Left" Margin="45,70,0,0" Grid.Row="1"       
      VerticalAlignment="Top" MinWidth="200" MinHeight="200"
      ItemTemplate="{StaticResource PatientInfoTemplate}"
      ItemsPanel="{StaticResource GridViewItemsWisePanel}"          
      BorderBrush="White" BorderThickness="2"
      ScrollViewer.VerticalScrollBarVisibility="Auto"
      ScrollViewer.HorizontalScrollBarVisibility="Visible"
      SelectionMode="Single" MaxWidth="1000"
      ItemsSource="{Binding Source={StaticResource PatientsCollection}}">
   <GridView.GroupStyle>
    <GroupStyle>
     <GroupStyle.HeaderTemplate>
      <DataTemplate>
       <TextBlock Text='{Binding HospitalName}'
Foreground="Red" FontSize="25" Margin="5" Width="200"/>
      </DataTemplate>
     </GroupStyle.HeaderTemplate>
    </GroupStyle>
   </GridView.GroupStyle>
  </GridView>
</SemanticZoom.ZoomedInView>
</SemanticZoom>
       

The SemanticZoom contains ZoomedOutView and ZoomedInView with GridView controls in it. The GridView in the ZoomedInView is set with the ItemsSource property to the PatientsCollection CollectionVeiwSource defined resources.

Step 4: Add the following code in the Page Load event of the MainPage.Xaml.cs:

private  void Page_Loaded_1(object sender, RoutedEventArgs e)
{
//Get Patients
Patients = objDs.GetPatients();
HospitalNameGroup = new ObservableCollection<HospitalGroup>();
 
//Create a Group of Patients Group be HospitalName
var HospitalwiseGroup = Patients.GroupBy(d => d.HospitalName).Select(d => new HospitalGroup() { HospitalName = d.Key, Patients = d.ToList() });

foreach (var item in HospitalwiseGroup.ToList())
{
  HospitalNameGroup.Add(item);
}

//Set the CollectionViewSource
PatientsCollection.Source = HospitalNameGroup;
//Bind the Groups in the Collection View Source to the ZoomedOutPatGridView
ZoomedOutPatGridView.ItemsSource =
  PatientsCollection.View.CollectionGroups;
}

The above code makes call to the DataAccess. Once the Patients data is fetched, it is arranged by group wise HospitalName and then it is bound with the PatientsCollection declared using CollectionViewSource.

Step 5: Run the application, the default is shown as ZoomedInView as shown above in the figure 2 (section - A Use Case). This represents the Patients details for all department and when the end-user clicks on the “-” button of the lower right, the result shown in Figure 2 will be displayed, which shows all the Hospital names. User can optionally click on a specific Hospital Name and view the patients in that hospital.

Conclusion

The SemanticZoom control is a Modern way to display hierarchical or groups of data in Windows Store Apps. It helps represent large set of the data intuitively, and that can be navigated easily on small touch devices like tablets or on traditional desktop apps.

Download the entire source code at https://github.com/dotnetcurry/winrt-semantic-zoom-control

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Siva on Friday, April 19, 2013 1:35 AM
Thank you Mahesh. I got my answer