Application Bar Icon buttons are a look-and-feel-wise very consistent and easy to understand way for every Windows Phone 7 application to give it’s users access to the most important functions. The drawback of this thing is that it’s not a real FrameworkElement, thus you cannot bind commands and other stuff to it, but as I described earlier, this has been solved by the BindableApplicationBar.
But even the BindableApplicationBar has its issues. The IconUri attribute of a BindableApplicationBarIconButton cannot be bound to – for it is no Dependecy Property. Now you can fix that, since Nicolas Humann includes the source code of his excellent solution. But I prefer to threat someone else’s code as third party component, and solved the problem using a very powerful way of extending of Silverlight/Windows Phone 7: attached dependency properties.
The problem I wanted to solve is this: I have changed my MapMania App in such a way that it now tracks your location continually if you press the “Satellite” button. But I want the user to be able to stop tracking as well, using the same button. So what used to be a simple activation button, is now a toggle button. When the user is tracking his own phone, I want the button image to change from the image of of a satellite to an image of a satellite with a big cross through it, indicating “if you press me again, I will stop tracking”. And I wanted this, of course, to be steered from the viewmodel.
This is how I solved it, with three attached dependency properties:
using System;
using System.Windows;
using Phone7.Fx.Preview;
namespace LocalJoost.Utilities
{
/// <summary>
/// Supports toggle of a BindableApplicationBarIconButton's icon
/// </summary>
public static class AppBarIconFlipper
{
#region IconUri
public static readonly DependencyProperty IconUriProperty =
DependencyProperty.RegisterAttached("IconUri",
typeof(Uri),
typeof(AppBarIconFlipper),
new PropertyMetadata(IconUriPropertyChanged));
// Called when Property is retrieved
public static Uri GetIconUri(DependencyObject obj)
{
return obj.GetValue(IconUriProperty) as Uri;
}
// Called when Property is set
public static void SetIconUri(
DependencyObject obj,
Uri value)
{
obj.SetValue(IconUriProperty, value);
}
// Called when property is changed
private static void IconUriPropertyChanged(
object sender,
DependencyPropertyChangedEventArgs args)
{
var attachedObject = sender as BindableApplicationBarIconButton;
if (attachedObject == null) return;
attachedObject.IconUri = (bool)attachedObject.GetValue(ShowAlernateIconUriProperty)
? (Uri)attachedObject.GetValue(AlernateIconUriProperty)
: (Uri)args.NewValue;
}
#endregion
#region AlernateIconUri
public static readonly DependencyProperty AlernateIconUriProperty =
DependencyProperty.RegisterAttached("AlernateIconUri",
typeof(Uri),
typeof(AppBarIconFlipper),
new PropertyMetadata(AlernateIconUriPropertyChanged));
// Called when Property is retrieved
public static Uri GetAlernateIconUri(DependencyObject obj)
{
return obj.GetValue(AlernateIconUriProperty) as Uri;
}
public static void SetAlernateIconUri(
DependencyObject obj,
Uri value)
{
obj.SetValue(AlernateIconUriProperty, value);
}
private static void AlernateIconUriPropertyChanged(
object sender,
DependencyPropertyChangedEventArgs args)
{
var attachedObject = sender as BindableApplicationBarIconButton;
if (attachedObject == null) return;
attachedObject.IconUri = (bool)attachedObject.GetValue(ShowAlernateIconUriProperty)
? (Uri)args.NewValue
: (Uri)attachedObject.GetValue(IconUriProperty);
}
#endregion
#region ShowAlernateIconUri
public static readonly DependencyProperty ShowAlernateIconUriProperty =
DependencyProperty.RegisterAttached("ShowAlernateIconUri",
typeof(bool),
typeof(AppBarIconFlipper),
new PropertyMetadata(ShowAlernateIconUriPropertyChanged));
public static bool GetShowAlernateIconUri(DependencyObject obj)
{
return (bool)obj.GetValue(ShowAlernateIconUriProperty);
}
public static void SetShowAlernateIconUri(
DependencyObject obj,
bool value)
{
obj.SetValue(ShowAlernateIconUriProperty, value);
}
private static void ShowAlernateIconUriPropertyChanged(
object sender,
DependencyPropertyChangedEventArgs args)
{
var attachedObject = sender as BindableApplicationBarIconButton;
if (attachedObject == null) return;
var value = (bool)args.NewValue;
attachedObject.IconUri = value
? (Uri)attachedObject.GetValue(AlernateIconUriProperty)
: (Uri)attachedObject.GetValue(IconUriProperty);
}
#endregion
}
}
The only interesting code is in the “***Changed” methods, the rest is just the necessary plumbing. Anyway, in stead of setting the IconUri of the BindableApplicationBarIconButton directly, you use the attached dependency properties like this:
<Phone7Fx:BindableApplicationBarIconButton
Command="{Binding ShowLocation}" Text="Track"
LocalJoostUtils:AppBarIconFlipper.IconUri="/icons/gps.png"
LocalJoostUtils:AppBarIconFlipper.AlernateIconUri="/icons/gps_stop.png"
LocalJoostUtils:AppBarIconFlipper.ShowAlernateIconUri="{Binding IsTracking, Mode=TwoWay}"/>
and depending on the value of the Viewmodel property IsTracking the icon will flip from gps.png (false) to gps_stop (true) – or back.
Once again it shows Microsoft’s XAML-based platforms are as flexible as a rubber band, and wherever are holes in binding, you can almost always plug them using attached dependency properties – the super glue of MVVM, IMHO.

