Colin Eberhardt's Technology Adventures

Visiblox MVP Giveaway

June 23rd, 2011

Readers of my blog will probably have noticed that I have a keen interest in both charting and performance. My friends over at Visiblox have combined these both to create what is one of the fastest charts for WPF, Silverlight and Windows Phone 7, see my recent benchmark blog post for details. What’s more, this performance has been achieved without sacrificing API clarity; the Visiblox charts can be instantiated with concise and clean XAML or manipulated from code-behind.

The guys at Visiblox told me that they are giving away free licences for their charting products to anyone who is a current Microsoft MVP, so I thought I’d share that with you in case you’re interested. For more details on this offer please contact Visiblox directly.

If you are an MVP, give these charts a whirl …

I’d better get back to work on the cross-platform (WPF, Silverlight, WP7) application that I will be demoing at the next Silverlight UK User Group meeting, and yes, it uses Visiblox charts!

Regards, Colin E.

Metro In Motion #8 – AutoCompleteBox Reveal Animation

June 20th, 2011

When I started the Metro In Motion series, I thought I would probably post three or four articles and be done. However, every time I use my Windows Phone 7 I seem to spot a new ‘native’ fluid UI effect which I would like to use in my own code. Also, these posts have proven very popular, there appears to be a real developer ‘need’ for this sort of information.

In this instalment of Metro In Motion I will show how to implement the fluid auto-complete effect that can be seen in the Windows Phone 7 email client. You can see a ‘storyboard’ for this effect below; the items within the auto-complete popup slide gracefully into view when the popup initially renders:

This effect uses the AutoCompleteBox which is part of the Silverlight for Windows Phone Toolkit. I have implemented this effect as a Blend Behaviour, allowing it to be easily added to an AutoCompleteBox either via drag and drop within Expression Blend, or by simply adding the XAML below:

<tk:AutoCompleteBox VerticalAlignment="Top"
                    ItemsSource="{Binding}"
                    ValueMemberPath="Surname">
  <!-- add the metro in motion effect -->
  <i:Interaction.Behaviors>
    <behaviour:AutoCompleteSlideBehaviour/>
  </i:Interaction.Behaviors>
</tk:AutoCompleteBox>

Let’s take a look at how this behaviour is implemented …

In order for this effect to work, we need to handle the Opening event raised by the Popup control that is part of the AutoCompleteBox template. When this event fires, each of the elements within the ListBox that the Popup contains are animated. The first task is to locate the ListBox and the Popup, this is performed when the behaviour is attached:

protected override void OnAttached()
{
  base.OnAttached();
 
  // locate the listBox, if this fails, the AutoCOmpleteBox is not loaded,
  // so try again after the Loaded event.
  if (!TryFindListBox())
  {
    RoutedEventHandler onLoaded = null;
    onLoaded = (s, e) =>
        {
          TryFindListBox();
          AssociatedObject.Loaded -= onLoaded;
        };
    AssociatedObject.Loaded += onLoaded;
  }
}
 
/// <summary>
/// Tries to locate the Listbox within the auto-completes Popup.
/// </summary>
private bool TryFindListBox()
{
  // locate the auto-complete  popup
  _popup = AssociatedObject.Descendants<Popup>().SingleOrDefault() as Popup;
  if (_popup == null)
    return false;
 
  _popup.Opened += Popup_Opened;
 
  // locate the ListBox
  _popUpListbox = _popup.Child.Descendants<ListBox>().SingleOrDefault() as ListBox;
  return true;
}

The above code uses some simple Linq-to-VisualTree to locate these elements. Notice that the approach taken first tries to locate these elements, if this fails, the Loaded event is handled, which is fired when elements (and their template components) are added to the visual tree.

The animation is fired each time the Popup is opened. Creating the animation itself is quite simple, the items within the ListBox are iterated over, with a TranslateTransform created for each, with delayed Storyboard animations used to fire the animations sequentially. However, the container’s (i.e. ListBoxItem instances) may not have been created when the Opened event fires. In order to handle this, the code below checks for the container of the item at the first index. If this container has not yet been generated, the code which creates the animations is deferred until after the next LayoutUpdated event. This should ensure that the containers are now present. The code is shown below:

/// <summary>
/// Handle the Opened even on the Popup in order to animate the contents
/// </summary>
private void Popup_Opened(object sender, System.EventArgs e)
{
  if (_popUpListbox.Items.Count == 0)
    return;
 
  // an action which fires the required animation for each element
  Action fireAnimations = () =>
  {
    // locate all the ListBoxItems
    var itemContainers = _popUpListbox.Items
        .Select(i => _popUpListbox.ItemContainerGenerator.ContainerFromItem(i))
        .Where(i => i != null)
        .Cast<ListBoxItem>();
 
    // animate each item
    double startTime = 0;
    foreach (var listBoxItem in itemContainers)
    {
      // add a render transform that offsets the element
      var trans = new TranslateTransform()
          {
            Y = -50
          };
      listBoxItem.RenderTransform = trans;
      listBoxItem.Opacity = 0.0;
 
      var sb = new Storyboard();
      sb.BeginTime = TimeSpan.FromMilliseconds(startTime);
      sb.Children.Add(TiltBehaviour.CreateAnimation(null, 0, 0.2, "Y", trans));
      sb.Children.Add(TiltBehaviour.CreateAnimation(null, 1, 0.5, "Opacity", listBoxItem));
      sb.Begin();
 
      startTime += 100;
    }
  };
 
  // check if the item container for the first item has been generated
  if (_popUpListbox.ItemContainerGenerator.ContainerFromIndex(0) == null)
  {
    // if not, wait for the next LayoutUpdated event
    EventHandler updateHandler = null;
    updateHandler = (s, e2) =>
    {
      fireAnimations();
      _popUpListbox.LayoutUpdated -= updateHandler;
    };
    _popUpListbox.LayoutUpdated += updateHandler;
  }
  else
  {
    // otherwise, fire the animations now
    fireAnimations();
  }
}

The full sourcecode for this behaviour can be found in the WP7Contrib project, within the WP7Contrib.View.Controls assembly.

You can download a simple working example here: MetroInMotionEight.zip

I have of course updated the Sandwich Flow, Metro In Motion demo application to include this effect. Again, this is available via the WP7Contrib project:

Regards,
Colin E.

Metro In Motion Part #7 – Panorama Prettiness and Opacity

June 14th, 2011

This blog post details a simple metro-in-motion behaviour which reduces the Panorama control’s contents while the user slides from item-to-item so that they can really appreciate your fancy background graphic!

For those of you who have not been following my Metro-In-Motion series, I’ll briefly recap. My aim is to provide an implementation of the ‘fluid’ UI transitions and effects seen in native Windows Phone 7 applications but absent from the Silverlight APIs. So far I have covered fluid list animations, ‘peel’ animations, flying titles, a ’tilt’ effect and a rolling list location indicator. In this post I look at a very simple and subtle effect, reducing the opacity of your Panorama contents when the user slides from item-to-item.

The Panorama is probably the prettiest of all the Windows Phone 7 controls, it really embodies what the Metro Design Language is all about. Typically a pretty graphic is used as a background for the Panorama as follows:

<controls:Panorama Title="Panorama">
  <controls:Panorama.Background>
    <ImageBrush ImageSource="PanoramaBackground.jpg" Opacity="0.5"/>
  </controls:Panorama.Background>
 
  <!-- panorama content goes here -->
 
</controls:Panorama>

Note, in the example above, the opacity of the image is reduced to 0.5 in order that it is not too bold and overpowering.

Unfortunately, our beautiful background graphic is almost entirely obscured by the panorama contents. The native applications, such as the pictures and games hubs, use a cunning little trick to allow the user to enjoy the background, whilst the user is sliding the Panorama, the contents become opaque, making the background visible behind the various tiles. That is the effect I will re-create in this blog post.

The code to achieve this effect is very simple. It is a basic Blend Behaviour, which handles the Panorama ManipulationDelta event in order to set the item’s Opacity, with the ManipulationCompleted event handler resetting the Opacity to 1.0.

The behaviour is show in its entirety below:

/// <summary>
/// This behaviour, when associated with a Panorama control, will reduce the opacity
/// of each PanoramaItem while the user slides the control.
/// </summary>
public class PanoramaOpacityBehaviour : Behavior<Panorama>
{
    #region DPs
 
    /// <summary>
    /// Gets or sets the opacity used for the panorama items whilst the user is 'sliding'
    /// </summary>
    [Description("Indicates the opacity used for the panorama items whilst the user is 'sliding'")]
    [Category("Appearance")]
    public double Opacity
    {
        get { return (double)GetValue(OpacityProperty); }
        set { SetValue(OpacityProperty, value); }
    }
 
    /// <summary>
    /// Identifies the Opacity dependency property
    /// </summary>
    public static readonly DependencyProperty OpacityProperty =
        DependencyProperty.Register("Opacity", typeof(double),
        typeof(PanoramaOpacityBehaviour), new PropertyMetadata(0.7));
 
    #endregion
 
 
    #region overrides
 
    protected override void OnAttached()
    {
        base.OnAttached();
 
        AssociatedObject.ManipulationDelta += Panorama_ManipulationDelta;
        AssociatedObject.ManipulationCompleted += Panorama_ManipulationCompleted;
    }
 
    protected override void OnDetaching()
    {
        base.OnDetaching();
 
        AssociatedObject.ManipulationDelta -= Panorama_ManipulationDelta;
        AssociatedObject.ManipulationCompleted -= Panorama_ManipulationCompleted;
    }
 
    #endregion
 
    #region private
 
    private void Panorama_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
    {            
        foreach (FrameworkElement fe in AssociatedObject.Items)
        {
            // restore the previous opacity
            fe.Opacity = 1.0;
        }
    }
 
    private void Panorama_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        foreach (FrameworkElement fe in AssociatedObject.Items)
        {
            // store the opacity and set the new value
            fe.Opacity = Opacity;
        }
    }
 
    #endregion
}

This behaviour can be applied programmatically as follows:

<controls:Panorama Title="Panorama">
  <i:Interaction.Behaviors>
    <WP7Contrib_View_Controls_Behaviors:PanoramaOpacityBehaviour/>
  </i:Interaction.Behaviors>
  <controls:Panorama.Background>
    <ImageBrush ImageSource="PanoramaBackground.jpg" Opacity="0.5"/>
  </controls:Panorama.Background>
 
  <!-- panorama content goes here -->
 
</controls:Panorama>

Or applied by drag and drop within Expression Blend:

With this behaviour applied, the user can now fully appreciate your Panorama control’s beautiful background graphic:

You can download the sourcecode for this behaviour and an example project here: MetroInMotionSeven.zip

I have also added this behaviour to the WP7Contrib project on codeplex. I would recommend that anyone doing WP7 development should download the WP7Contrib code, it is packed full of useful utilities.

Regards, Colin E.

Metro In Motion Part #6 – Rolling List Location Indicator

June 6th, 2011

This blog post describes the development of a rolling list location indicator. This indicator mirrors the behaviour seen in the native Windows Phone 7 calendar which rolls from one date to the next as the user scrolls.

For those of you who have not been following my Metro-In-Motion series, I’ll briefly recap. My aim is to provide an implementation of the ‘fluid’ UI transitions and effects seen in native Windows Phone 7 applications but absent from the Silverlight APIs. So far I have covered fluid list animations, ‘peel’ animations, flying titles , a ’tilt’ effect and finally SandwichFlow which brought all these effects together and the series to a close. However, a recent StackOverflow questions inspired me to implement another fluid UI effect found in the native calendar application. When scrolling your list of appointments, the small day indicator at the top of the page displays the current date, with graceful roll transitions as you move from day-to-day:

It’s a subtle but the effect is very pleasing!

You can see my implementation of this effect in the video below:

In order to create this indicator, we need to determine the item that is currently at the top of the list while it is being scrolled, and the direction of scrolling. Once we have this data at our disposal, the rest is all just visualisation!

Finding the head of the list

The Silverlight ListBox and ItemsControl do not expose a property which indicates the first visible item, so we need to add this functionality. Adding the properties themselves is simply a matter of defining a FirstVisibleItem and a IsScrollingUpwards attached properties. The logic that computes these properties is a little more complicated!

I have created a boolean ExposeFirstVisibleItem attached property (which acts as an attached behaviour). When this property is set to true, we navigate the visual tree to locate the vertical scrollbar that is located within the ScrollViewer which is part of the ListBox template.

The changed event handler for this attached property is shown below:

private static void OnExposeFirstVisibleItemPropertyChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
  if (e.NewValue.Equals(true))
  {
    ItemsControl itemsControl = d as ItemsControl;
 
    // wire up the scrollbar, handling ValueChanged events
    if (!WireUpScrollbar(itemsControl))
    {
      // if wire-up fails, try again on LayoutUpdated
      EventHandler tryFindScrollBar = null;
      tryFindScrollBar = (s2, e2) =>
      {
        if (WireUpScrollbar(itemsControl))
        {
          itemsControl.LayoutUpdated -= tryFindScrollBar;
        }
      };
 
      itemsControl.LayoutUpdated += tryFindScrollBar;
    }
  }
}

Note, the method WireUpScrollbar returns true if it has located the scrollbar. However, if the template for our ListBox has not yet been instantiated this will fail. In this case, we handle the LayoutUpdated event and retry until this method returns a success. Note, the EventHandler that removes its own subscription to the LayoutUpdated event, a neat pattern that I will certainly use again!

The WireUpScrollbar method uses Linq-to-VisualTree to locate the ScrollBar.

private static bool WireUpScrollbar(ItemsControl itemsControl)
{
  var sb = itemsControl.Descendants<ScrollBar>()
                      .Cast<ScrollBar>()
                      .Where(s => s.Orientation == Orientation.Vertical)
                      .SingleOrDefault() as ScrollBar;
 
  if (sb == null)
    return false;
 
  // set to the initial value
  SetFirstVisibleItem(itemsControl);
  sb.Tag = sb.Value;
 
  // update value on scroll ...
  sb.ValueChanged += (s, e2) =>
  {
    SetFirstVisibleItem(itemsControl);
    SetIsScrollingUpwards(itemsControl, sb.Value < (double)sb.Tag);
 
    // store the previous scroll position in the Tag
    sb.Tag = sb.Value;
  };
 
  return true;
}

The ScrollBar.Tag is used to store the previous scroll location so that we can determine the scroll direction, with SetIsScrollingUpwards setting the attached property on our ListBox (or ItemsControl).

Finally SetFirstVisibleItem locates the first visible item within the list and updated the FirstVisibleItem attached property:

private static void SetFirstVisibleItem(ItemsControl itemsControl)
{
  itemsControl.Dispatcher.BeginInvoke(() =>
  {
    var item = itemsControl.GetItemsInView().First();
    ListUtils.SetFirstVisibleItem(itemsControl, item.DataContext);
  });
}

Note the GetItemsInView extension method which enumerates the visible items. This was implemented in an earlier Metro-In-Motion blog post, however I have extended this implementation to support both virtualizing and non-virtualizing panels, you can see the latest version on codeplex within the Windows Phone 7 Contrib (WP7Contrib) project. The FirstVisibleItem exposes the DataContext of the first visible item, which will be the first visible model object.

Visualising the top item

With the above code, we simply set the following attached property to true on a ListBox or ItemsControl in order for it to expose teh first visible item and scroll direction:

<ListBox mim:ListUtils.ExposeFirstVisibleItem="true" />

The rollover effect seen in the native control is very easy to reproduce with the Silverlight Toolkit TransitioningContentControl, which has proven popular with Silverlight developers wishing to create page transitions. The only problem is that this control has not made it into the WP7 version of the toolkit. So I simply grabbed the source of and placed it directly into my project.

If we look at the calendar example that is shown in the video at the start of this blog post, it has the following XAML:

<StackPanel x:Name="TitlePanel" Grid.Row="0">
 
  <layout:TransitioningContentControl
                Content="{Binding Path=(mim:ListUtils.FirstVisibleItem).Time,
                                   ElementName=list,
                                   Converter={StaticResource StringFormatConverter},
                                   ConverterParameter='dd MMM yy'}"
                Transition="{Binding Path=(mim:ListUtils.IsScrollingUpwards),
                                   ElementName=list,
                                   Converter={StaticResource BooleanToTransitionConverter}}">
    <layout:TransitioningContentControl.ContentTemplate>
      <DataTemplate>
        <TextBlock Text="{Binding}"
                        FontSize="60"/>
      </DataTemplate>
    </layout:TransitioningContentControl.ContentTemplate>
  </layout:TransitioningContentControl>
</StackPanel>
 
<Grid x:Name="ContentPanel" Grid.Row="1" >
  <ListBox ItemsSource="{Binding}"
            x:Name="list"
            mim:ListUtils.ExposeFirstVisibleItem="true">
    <!-- template goes here -->
  </ListBox>
</Grid>

Which gives the following layout:

The Content property of our TransitioningContentControl uses ElementName binding and a property path of (mim:ListUtils.FirstVisibleItem).Time, in order to bind to the Time property of the first visible model object. Note that the list contains multiple items that are on the same day but have different times. The Converter associated with this binding (which is a simple implementation of the Silverlight 4 StringFormat binding property), uses the string 'dd MMM yy', which will give the same value for all appointments on the same day. Therefore the content of the TransitioningContentControl control will only change as we navigate between day boundaries.

The TransitioningContentControl already has suitable transitions which give a nice roll-up and roll-down effect. These are selected by setting the Transition property to the named transition. In the example above, this is bound to the attached boolean IsScrollingUpwards property of our list, with a simple value converter that converts this into the required string transition identifier.

And we’re done!

I quite like the way that the implementation of this effect is split into two halves, the one which extends the functionality of the list, and the other which visualises the output. This should give great flexibility, as can be seen in the example which indicates the list location within a contacts list.

This code also works with the Jump List I created a few months ago, however, it did require a few changes to that code. My current plan is to move all of the WP7 controls and effects I have created into the WP7Contrib project, so watch this (or that) space!).

You can download the sourcecode for this blog here: MetroInMotionSix.zip

Regards,
Colin E.