01 February 2014

Build for both–a very simple wp8 style app bar hint control for Windows Store apps

Windows Phone users are very familiar with the concept of an app bar at the bottom that, in collapsed state, gives a kind of indication that it’s available. In Windows Store apps app bars are just invisible, unless you specifically activate them by swiping in from the top or the bottom. There have been earlier attempts to solve this UI difference by my fellow Dutch MVP Fons Sonnemans who created the Peeking App Bar. Microsoft itself has apparently become aware of the fact default invisible app bars may not always be ideal, and has created a kind of a hint of an app bar that very much looks like they had some inspiration from Windows Phone – which is now used in the Windows Mail app:

image

Now there are already solutions out there, most notably this one by recently appointed MVP Dave Smits. They work indeed. But I like to make things simple, so I made a very simple. So in a typical programmer fashion, I rolled my own :-)

So I created my HintBar control, which is actually laughably simple. The XAML is only this, and most of it is declaration too:

<UserControl
    x:Class="WpWinNl.Controls.HintBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="14"
    d:DesignWidth="400" x:Name="ControlRoot">

  <Grid x:Name="HintBarGrid" 
        Background="{Binding Background, ElementName=ControlRoot}" 
        Tapped="HintBarGridTapped">
    <TextBlock  x:Name="HintBarText" Text="&#xE10C" 
                FontFamily="Segoe UI Symbol" FontSize="21.333" 
                HorizontalAlignment="Right"  RenderTransformOrigin="0.5,0.5" 
                VerticalAlignment="Center" Margin="0,0,50,0"/>
  </Grid>
</UserControl>

So it’s basically a simple grid that does something when the user taps on it. In the grid there’s only a TextBlock with one ‘glyph’ in it – using the special Segoe UI Symbol character set that Microsoft uses to store all kinds of symbols in. &#xE10C is simply the code for a symbol containing three dots.

The code is not very complex either. It’s basically two attached dependency properties:

  • AssociatedCommandBar, to which you can bind the CommandBar to open when the hint bar is tapped
  • ForeGround, which you can use to change the color of the three dots

If you don’t understand what attached dependency properties are: they are basically the property equivalent of extension methods, and what’s more important – you can data bind to them.

So the AssociatedCommandBar looks like this. It does nothing special

#region Attached Dependency Property AssociatedCommandBar
public static readonly DependencyProperty AssociatedCommandBarProperty =
	 DependencyProperty.RegisterAttached("AssociatedCommandBar",
	 typeof(CommandBar),
	 typeof(HintBar),
	 new PropertyMetadata(default(CommandBar)));

// Called when Property is retrieved
public static CommandBar GetAssociatedCommandBar(DependencyObject obj)
{
  return obj.GetValue(AssociatedCommandBarProperty) as CommandBar;
}

// Called when Property is set
public static void SetAssociatedCommandBar(
   DependencyObject obj,
   CommandBar value)
{
  obj.SetValue(AssociatedCommandBarProperty, value);
}
#endregion

The other property is only a brush defining the text color, and the only thing it does is transferring its value to the text:

#region Attached Dependency Property ForeGround
public static readonly DependencyProperty ForeGroundProperty =
	 DependencyProperty.RegisterAttached("ForeGround",
	 typeof(Brush),
	 typeof(HintBar),
	 new PropertyMetadata(default(Brush), ForeGroundChanged));

// Called when Property is retrieved
public static Brush GetForeGround(DependencyObject obj)
{
  return obj.GetValue(ForeGroundProperty) as Brush;
}

// Called when Property is set
public static void SetForeGround(
   DependencyObject obj,
   Brush value)
{
  obj.SetValue(ForeGroundProperty, value);
}

// Called when property is changed
private static void ForeGroundChanged(
 object sender,
 DependencyPropertyChangedEventArgs args)
{
  var thisObject = sender as HintBar;
  if (thisObject != null)
  {
    thisObject.HintBarText.Foreground = args.NewValue as Brush;
  }
}
#endregion

And the rest of the ‘real code’ of the control is just this:

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;

namespace WpWinNl.Controls
{
  public sealed partial class HintBar : UserControl
  {
    public HintBar()
    {
      InitializeComponent();
    }

    private void HintBarGridTapped(object sender, 
	                           TappedRoutedEventArgs e)
    {
      var commandBar = GetAssociatedCommandBar(this);
      if (commandBar != null)
      {
        commandBar.IsOpen = true;
      }
    }
  }
}

Not exactly rocket science, right? You tap the grid, the command bar opens. :-)

Using it is pretty simple too. You have a page with a command bar:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:controls="using:WpWinNl.Controls"
    x:Class="HintBarDemo.MainPage"
    mc:Ignorable="d" VerticalAlignment="Bottom">

  <Page.BottomAppBar >
    <CommandBar x:Name="BottomBar"  Background="Blue">
    <!-- Content omitted -->
    </CommandBar>
  </Page.BottomAppBar>

  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <controls:HintBar Background ="Blue" Height="14" VerticalAlignment="Bottom"
     	   AssociatedCommandBar="{Binding ElementName=BottomBar}"/>

  </Grid>
</Page>

Give the command bar a name and bind it to AssociatedCommandBar property of the control. Then it’s just a matter of setting it to the bottom of the page, setting it to the desired height, and choosing a color for your bar. That is all. Life is sometimes very easy.

As always, the demo solution can be found here.

No comments: