Colin Eberhardt's Technology Adventures

Google Sky on Windows Phone 7

February 21st, 2011

This blog post shows just how easy it is to use Google Sky as a tile source for Bing Maps, bringing the universe to Windows Phone 7!

Personally I think mapping is one of the most exciting forms of application for mobile devices – the fantastic imagery available from Bing and Google maps, coupled with GPS technology, results in some pretty amazing tools. As a Windows Phone 7 developer, I have spent a fair bit of time poking round the Silverlight Bing Maps APIs. A really cool feature of the Bing Maps control is that it accepts custom tile-sources. You can find code elsewhere that explains how to use this to render Google Maps data via a Bing maps chart control. For a bit of fun I decided to use this approach to render Google Sky on WP7 …

Finding the correct URL format is as easy as opening up firebug and looking at the HTTP traffic when using Google Sky:

With this knowledge, creating a custom tile source for Bing maps is pretty trivial

public class GoogleTile : Microsoft.Phone.Controls.Maps.TileSource
{
    public GoogleTile()
    {
        UriFormat = @"http://mw1.google.com/mw-planetary/sky/skytiles_v1/{0}_{1}_{2}.jpg";
    }
 
    public override Uri GetUri(int x, int y, int zoomLevel)
    {
        if (zoomLevel > 0)
        {
            var Url = string.Format(UriFormat, x, y, zoomLevel);
            return new Uri(Url);
        }
        return null;
    }
}

And associating your tile source with a map control is as simple as this …

<map:Map Name="map"
    CopyrightVisibility="Collapsed" LogoVisibility="Collapsed" ScaleVisibility="Collapsed"
    ZoomLevel="2"
    CredentialsProvider="-- YOUR API KEY GOES HERE!!! ---">
    <map:Map.Mode>
        <mapCore:MercatorMode/>
    </map:Map.Mode>
    <map:MapTileLayer>
        <map:MapTileLayer.TileSources>
            <local:GoogleTile/>
        </map:MapTileLayer.TileSources>
    </map:MapTileLayer>
</map:Map>

When exploring the sky, funnily enough, it becomes pretty obvious that most of it is black! In order to make this a more interesting application I added a little ‘menu’ across the bottom that allows you to select from the list of 110 Messier Objects, a catalogue of interesting astronomical objects that are not comets. The thumbnail images for each object were scraped from Wikipedia, and the coordinates retrieved from the SIMBAD astronomical database via a little C# command line app.

They are rendered in the UI via an ItemsControl:

<ItemsControl x:Name="MessierObjects"
                Grid.Row="2">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid Width="100" Height="100"
                    MouseLeftButtonUp="Grid_MouseLeftButtonUp">
                <Image Source="{Binding Path=ThumbSource}"
                        Stretch="Fill" Margin="5"/>
                <TextBlock Text="{Binding Path=Name}"
                            Margin="5"
                            FontSize="25" FontWeight="Bold"
                            Foreground="LightGray"
                            Opacity="0.5"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer HorizontalScrollBarVisibility="Visible">
                <ItemsPresenter/>
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>

With a click handler that navigates the map control to the correct location:

private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    var messier = ((FrameworkElement)sender).DataContext as MessierObject;
 
    map.SetView(messier.Coords, 11);
}

I would love to build this application further, however, usage of Google Maps tiles outside of their service is a violation of their terms and conditions. For that reason, this code is shown just for a bit of fun, it shows easy it is to bring together two different technologies, Bing Maps and the Google Sky tile imagery, to create something cool with very few lines of code.

As an aside, I would have liked to have used the data from the less well know Microsoft WorldWide Telescope, which is accessible through Bing Maps, but just couldn’t work out the tile URL format. This is a shame, I would be happier building this application further based on a Microsoft datasource.

You can download the sourcecode here: GoogleSkyWP7.zip

Regards,
Colin E.

Windows Phone 7 Performance Measurements – Emulator vs. Hardware

February 11th, 2011

This blog post presents a few performance measurements that detail the relative performance of ItemsControl, ListBox and manual addition of elements to the UI. These performance measurements are also compared when ran on the emulator and the real hardware.

My early experiences of moving from the WP7 emulator to the real hardware revealed that performance is something that needs to be considered when developing an application. The complexity of the UI has a noticeable impact on the time to render a page. These findings lead me to develop the DeferredLoadContentControl which I blogged about a few days ago. In this blog post I want to explore various ways in which a UI may be constructed and their relative performance.

The test I constructed was quite simple, the MainPage has a number of buttons, each of which navigates to a new page. When the navigation is initiated, the timer starts, and when the Loaded event fires on the target page, the timer is stopped. This accurately records the wait that the user experiences in navigating.

My tests each construct a number of buttons and add them to the UI. Each test is run twice, once to construct 10 buttons, and another time to create 100. The tests are briefly described below:

  1. Buttons created in XAML
  2. Buttons created in code-behind and added to the visual tree.
  3. Buttons created via a ListBox (bound to a list of strings).
  4. Buttons created in code and added to a ListBox as its ItemsSource.
  5. Buttons created via a ItemsControl (bound to a list of strings), with a StackPanel as the ItemsPanel.
  6. Buttons created via a ItemsControl (bound to a list of strings), with a VirtualizingStackPanel as the ItemsPanel.
  7. And finally, an empty page!

Each test was performed 5 times, with an average result taken. Here are my findings, where the tests are being executed on a Samsung Omnia WP7 device:

I also ran the tests for populating the UI with 100 buttons on the emulator:

My conclusions are as follows:

  • Constructing the UI in code-behind or via XAML takes the same amount of time. Use whichever works best for you.
  • Using an ItemTemplate to construct the buttons doesn’t have a performance impact, taking the same amount of time to render the UI as if the buttons are added directly as children of the ListBox (or other items control).
  • Virtualization makes the rendering of a large number of items much faster, 1322ms vs. 685ms, for the ItemsControl. NOTE: The ListBox default template uses the VirtualizingStackPanel.
  • Virtualization makes the rendering of a small number of items a little bit slower.
  • An ItemsControl (when virtualizing) is faster at rendering 100 buttons than a ListBox, 982ms vs. 685ms.
  • The emulator is approximately four times faster than the real hardware!

I will certainly use the above information to guide the way that I develop WP7 applications, hopefully this data will help others too.

A few take-home messages …

Firstly, because the ItemsControl (when virtualizing) is faster than the ListBox, don’t use a ListBox for navigation … I have seen a number of examples where a ListBox is used to render items such as email messages, with the SelectionChanged event being used to initiate navigation. Use an ItemsControl, and handled the bubbled events instead!

Secondly, use techniques such as the DeferredLoadContentControl, or the DeferredLoadListBox to reduce the amount of UI elements added to the screen before its initial render.

Finally, test on real hardware!

You can download the code I used to make these measurements here: WindowsPhonePerformanceTests.zip

Regards,
Colin E.

A Circular ProgressBar Style using an Attached ViewModel

February 7th, 2011

This blog post describes how to re-template the Silverlight ProgressBar control to render a circular progress indicator. This approach uses an attached view model to circumnavigate some of the limitations of the ProgressBar design.

This blog post describes the creation of the following funky styles for the ProgressBar (and a bit of a rant about just what is wrong with the way that ‘lookless’ controls work!)

If you get sick of the spinning, click the pause button!

Introduction

A few days ago I answered a question on stack overflow which asked How create a Circular Style progressbar? (sic)

The answer which I gave, and most people seemed to agree with, was that to achieve this you would have to create your own control from ‘scratch’. I was happy that my answer was accepted, but at the same time a little unhappy that this should be the right answer. After all, Silverlight / WPF give you the power to create ‘lookless’ controls, and what is a circular progress bar if it isn’t just another skin or ‘look’ for the regular progress bar?

What is wrong with the ProgressBar?

If you look at the documentation for styling / templating the ProgressBar you will find that this control expects the template to contain two elements, ProgressBarTrack and ProgressBarIndicator:

What the ProgressBar does is, when the template is applied, in OnApplyTemplate, it locates the elements with the given names in order to update the visual state of the UI. You can use Reflector (quick, while it is still free!) to see how the state of these elements is updated in the ProgressBar.SetProgressBarIndicatorLength method:

private void SetProgressBarIndicatorLength()
{
    double minimum = base.Minimum;
    double maximum = base.Maximum;
    double num3 = base.Value;
    if ((this.ElementTrack != null) && (this.ElementIndicator != null))
    {
        FrameworkElement parent = VisualTreeHelper.GetParent(this.ElementIndicator) as FrameworkElement;
        if (parent != null)
        {
            double num4 = this.ElementIndicator.Margin.Left + this.ElementIndicator.Margin.Right;
            Border border = parent as Border;
            if (border != null)
            {
                num4 += border.Padding.Left + border.Padding.Right;
            }
            else
            {
                Control control = parent as Control;
                if (control != null)
                {
                    num4 += control.Padding.Left + control.Padding.Right;
                }
            }
            double num5 = (this.IsIndeterminate || (maximum == minimum)) ? 1.0 : ((num3 - minimum) / (maximum - minimum));
            double num6 = Math.Max((double) 0.0, (double) (parent.ActualWidth - num4));
            this.ElementIndicator.Width = num5 * num6;
        }
    }
}

You can see in the above code that the various properties of the ElementTrack and ElementIndicator elements (the two named elements in the template) are being updated programmatically. This basically restricts the re-templating capabilities of the ProgressBar to ones where the ‘indicator’ element has a width which is some proportion of its parent element. That is not very lookless!

So what is so bad about creating your own circular progress indicator from scratch? Firstly, there is the issue of object-oriented design principles and re-use. Secondly, and in my opinion much more importantly, is how this affects skinning. Templating allows you to radically change your UI simply by applying a new set of styles, see for example the Silverlight Toolkit Themes. Styles can change the value of any property of an element (including its template) but they cannot change the class itself! So, if you create a circular progress bar as a new control, you cannot interchange it with the standard ProgressBar simply by applying a theme.

An Attached View Model

OK, rant over. Time to fix the problem!

A few months ago I blogged about how to create completely lookless controls using an attached view model. The basic concept behind this approach is that the control itself should not include any logic which is tightly-coupled to a particular template, or ‘look’. This logic is still required, but is instead introduced into the template by means of an attached view model.

Typically the elements within a control’s template inherit the same DataContext as the control itself, i.e. whatever business object or view model you have bound to your UI. With the attached view model approach, a view model is attached to the root element in the template. On attachment, this view model acquires a reference to the ProgressBar, in order to adapt its properties, making it easier to render a circular indicator, and sets itself as the DataContext of the child elements:

The view model is attached in XAMl as follows, as a result the DataContext of any element within the template is now the view model:

<ControlTemplate TargetType="ProgressBar">
  <Grid x:Name="LayoutRoot">
    <!-- attach the view model -->
    <local:CircularProgressBarViewModel.Attach>
      <local:CircularProgressBarViewModel/>
    </local:CircularProgressBarViewModel.Attach>
 
    <!-- the rest of the template now has CircularProgressBarViewModel as the DataContext -->
  </Grid>
</ControlTemplate>

Becoming Attached

The changed handler for the Attach property is given below. In summary, on attachment, the view model sets itself as the DataContext for the element it has been attached to. It then handlers the Loaded event which fires when the UI is fully constructed in order to locate the ProgressBar using Linq to VisualTree:

/// <summary>
/// Change handler for the Attach property
/// </summary>
private static void OnAttachChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  // set the view model as the DataContext for the rest of the template
  FrameworkElement targetElement = d as FrameworkElement;
  CircularProgressBarViewModel viewModel = e.NewValue as CircularProgressBarViewModel;
  targetElement.DataContext = viewModel;
 
  // handle the loaded event
  targetElement.Loaded += new RoutedEventHandler(Element_Loaded);
}
 
/// <summary>
/// Handle the Loaded event of the element to which this view model is attached
/// in order to enable the attached
/// view model to bind to properties of the parent element
/// </summary>
static void Element_Loaded(object sender, RoutedEventArgs e)
{
  FrameworkElement targetElement = sender as FrameworkElement;
  CircularProgressBarViewModel attachedModel = GetAttach(targetElement);
 
  // find the ProgressBar and associated it with the view model
  var progressBar = targetElement.Ancestors<ProgressBar>().Single() as ProgressBar;
  attachedModel.SetProgressBar(progressBar);
}

Once the view model is associated with the progress bar, it is able to compute properties which assist in the creation of a circular template, e.g. the angle used to represent a particular progress value.

/// <summary>
/// Add handlers for the updates on various properties of the ProgressBar
/// </summary>
private void SetProgressBar(ProgressBar progressBar)
{
  _progressBar = progressBar;
  _progressBar.SizeChanged += (s, e) => ComputeViewModelProperties();
  RegisterForNotification("Value", progressBar, (d,e) => ComputeViewModelProperties());
  RegisterForNotification("Maximum", progressBar, (d, e) => ComputeViewModelProperties());
  RegisterForNotification("Minimum", progressBar, (d, e) => ComputeViewModelProperties());
 
  ComputeViewModelProperties();
}
 
 
/// Add a handler for a DP change
/// see: http://amazedsaint.blogspot.com/2009/12/silverlight-listening-to-dependency.html
private void RegisterForNotification(string propertyName, FrameworkElement element, PropertyChangedCallback callback)
{
 
  //Bind to a dependency property  
  Binding b = new Binding(propertyName) { Source = element };
  var prop = System.Windows.DependencyProperty.RegisterAttached(
      "ListenAttached" + propertyName,
      typeof(object),
      typeof(UserControl),
      new PropertyMetadata(callback));
 
  element.SetBinding(prop, b);
}

Thanks to Anoop for publishing a nice and simple method for registering for change notification of dependency properties (what a pain that DPs do not also implement the INotifyPropertyChanged pattern!).

Each time one of the properties on the progress bar changes, the following method updates a few of the CLR properties exposed by the attached view model:

/// <summary>
/// Re-computes the various properties that the elements in the template bind to.
/// </summary>
protected virtual void ComputeViewModelProperties()
{
  if (_progressBar == null)
    return;
 
  Angle = (_progressBar.Value - _progressBar.Minimum) * 360 / (_progressBar.Maximum - _progressBar.Minimum);
  CentreX = _progressBar.ActualWidth / 2;
  CentreY = _progressBar.ActualHeight / 2;
  Radius = Math.Min(CentreX, CentreY);
  Diameter = Radius * 2;
  InnerRadius = Radius * HoleSizeFactor;
  Percent = Angle / 360;
}

The complete XAML for one of the styled progress bars seen at the top of this blog post is given below. Here you can see how the various UI elements within the template are bound to the attached view model:

<Style TargetType="ProgressBar" x:Key="PieProgressBarStyle">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ProgressBar">
        <Grid x:Name="LayoutRoot">
          <!-- attach the view model -->
          <local:CircularProgressBarViewModel.Attach>
            <local:CircularProgressBarViewModel HoleSizeFactor="0.75"/>
          </local:CircularProgressBarViewModel.Attach>
 
          <!-- a circular outline -->
          <Ellipse Width="{Binding Diameter}" Height="{Binding Diameter}"
                    HorizontalAlignment="Center" VerticalAlignment="Center"
                    Stroke="LightGray" Fill="Transparent"
                    StrokeThickness="0.3">
          </Ellipse>
 
          <!-- a pie-piece that indicates the progress -->
          <local:PiePiece CentreX="{Binding CentreX}" CentreY="{Binding CentreY}"
                          RotationAngle="0" WedgeAngle="{Binding Angle}"
                          Radius="{Binding Radius}" Fill="LightBlue"/>
 
          <!-- progress as a percent -->
          <Grid util:GridUtils.RowDefinitions="*,3.5*,*"
                util:GridUtils.ColumnDefinitions="*,3.5*,*">
            <TextBlock Text="{Binding Percent, StringFormat=0%}"
                        Foreground="DarkBlue"
                        FontWeight="Bold" FontSize="20"
                        Grid.Row="1" Grid.Column="1"
                        VerticalAlignment="Center" HorizontalAlignment="Center"/>
          </Grid>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

(The template uses a PiePiece is a control I borrowed from a PieChart control I created a few years back, and the simplified Grid syntax)

We now have a circular ProgressBar! …

Segmented Progress Bar

For a bit of fun I extended the attached view model to allow for the easy construction of circular progress bar sthat are rendered as discrete segments. The SegmentedProgressBarViewModel, which is attached to the template exposes a collection of objects which allow the creation of a segmented indicator via an ItemsControl. For full details,download the blog sourcecode.

<Style TargetType="ProgressBar" x:Key="SegmentedProgressBarStyle">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ProgressBar">
        <Grid x:Name="LayoutRoot">
          <!-- attach the view model -->
          <local:CircularProgressBarViewModel.Attach>
            <local:SegmentedProgressBarViewModel HoleSizeFactor="0.7"/>
          </local:CircularProgressBarViewModel.Attach>
 
          <!-- render the segments -->
          <ItemsControl ItemsSource="{Binding Segments}">
            <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                <Grid/>
              </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
              <DataTemplate>
                <Grid>
                  <!-- a grey segment -->
                  <local:PiePiece CentreX="{Binding Parent.CentreX}" CentreY="{Binding Parent.CentreY}"
                            RotationAngle="{Binding StartAngle}" WedgeAngle="{Binding WedgeAngle}"
                            Radius="{Binding Parent.Radius}" InnerRadius="{Binding Parent.InnerRadius}"
                            Fill="LightGray" Stroke="White" Opacity="0.5"/>
                  <!-- a blue segment, with an Opacity bound to the view model -->
                  <local:PiePiece CentreX="{Binding Parent.CentreX}" CentreY="{Binding Parent.CentreY}"
                            RotationAngle="{Binding StartAngle}" WedgeAngle="{Binding WedgeAngle}"
                            Radius="{Binding Parent.Radius}" InnerRadius="{Binding Parent.InnerRadius}"
                            Fill="DarkBlue" Stroke="White" Opacity="{Binding Opacity}"/>
                </Grid>
              </DataTemplate>
            </ItemsControl.ItemTemplate>                  
          </ItemsControl>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

The above markup results in the following style:

The sourcecode for this blog includes a few other styles, including a ‘glass’ effect which was borrowed from Pete Brown’s blog post on Pie chart styling.

Sourcecode

You can download the full sourcecode for this blog post: CircularProgressBar.zip

Regards, Colin E.