Binding the WP7 ProgressIndicator in XAML
The Mango beta of the Windows Phone 7 SDK saw the inclusion of a new way to display the progress of asynchronous operations within the phone's system tray. This is done using the new ProgressIndicator class, which is a DependencyObject that hooks in to the native progress bar in the system tray, and allows you to display a text message in the system tray, along with allowing you to control the progress bar that can handle both determinate and indeterminate states.
While the ProgressIndicator supports data-binding, the downside is that bindings need to be set up in the page code-beside; which is not very elegant. See the following example of a page constructor wiring up a ProgressIndicator:
public FooView()
{
InitializeComponent();
DataContext = new FooViewModel();
Loaded += (o, args) =>
{
var progressIndicator = SystemTray.ProgressIndicator;
if (progressIndicator != null)
{
return;
}
progressIndicator = new ProgressIndicator();
SystemTray.SetProgressIndicator(this, progressIndicator);
Binding binding = new Binding("Busy") { Source = ViewModel };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.IsVisibleProperty, binding);
binding = new Binding("Busy") { Source = ViewModel };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.IsIndeterminateProperty, binding);
binding = new Binding("Message") { Source = ViewModel };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.TextProperty, binding);
};
}
While completing my latest chapter of Windows Phone 7 Unleashed, on local databases, I spent a few minutes writing a wrapper for the ProgressIndicator. The ProgressIndicatorProxy, as it's called, can be placed in XAML, and doesn't rely on any code-beside:
<Grid x:Name="LayoutRoot" Background="Transparent">
<u:ProgressIndicatorProxy IsIndeterminate="{Binding Indeterminate}"
Text="{Binding Message}"
Value="{Binding Progress}" />
</Grid>
The element itself has no visibility; its task is to attach a ProgressIndicator to the system tray, and to provide bindable properties that flow through to the ProgressIndicator instance.
When the element's Loaded event is raised, it instantiates a ProgressIndicator, assigns it to the system tray, and binds its properties to the ProgressIndicatorProxy object's properties. The class is shown in the following excerpt:
public class ProgressIndicatorProxy : FrameworkElement
{
bool loaded;
public ProgressIndicatorProxy()
{
Loaded += OnLoaded;
}
void OnLoaded(object sender, RoutedEventArgs e)
{
if (loaded)
{
return;
}
Attach();
loaded = true;
}
public void Attach()
{
if (DesignerProperties.IsInDesignTool)
{
return;
}
var page = this.GetVisualAncestors<PhoneApplicationPage>().First();
var progressIndicator = SystemTray.ProgressIndicator;
if (progressIndicator != null)
{
return;
}
progressIndicator = new ProgressIndicator();
SystemTray.SetProgressIndicator(page, progressIndicator);
Binding binding = new Binding("IsIndeterminate") { Source = this };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.IsIndeterminateProperty, binding);
binding = new Binding("IsVisible") { Source = this };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.IsVisibleProperty, binding);
binding = new Binding("Text") { Source = this };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.TextProperty, binding);
binding = new Binding("Value") { Source = this };
BindingOperations.SetBinding(
progressIndicator, ProgressIndicator.ValueProperty, binding);
}
#region IsIndeterminate
public static readonly DependencyProperty IsIndeterminateProperty
= DependencyProperty.RegisterAttached(
"IsIndeterminate",
typeof(bool),
typeof(ProgressIndicatorProxy), new PropertyMetadata(false));
public bool IsIndeterminate
{
get
{
return (bool)GetValue(IsIndeterminateProperty);
}
set
{
SetValue(IsIndeterminateProperty, value);
}
}
#endregion
#region IsVisible
public static readonly DependencyProperty IsVisibleProperty
= DependencyProperty.RegisterAttached(
"IsVisible",
typeof(bool),
typeof(ProgressIndicatorProxy), new PropertyMetadata(true));
public bool IsVisible
{
get
{
return (bool)GetValue(IsVisibleProperty);
}
set
{
SetValue(IsVisibleProperty, value);
}
}
#endregion
#region Text
public static readonly DependencyProperty TextProperty
= DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(ProgressIndicatorProxy), new PropertyMetadata(string.Empty));
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
#endregion
#region Value
public static readonly DependencyProperty ValueProperty
= DependencyProperty.RegisterAttached(
"Value",
typeof(double),
typeof(ProgressIndicatorProxy), new PropertyMetadata(0.0));
public double Value
{
get
{
return (double)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
#endregion
}
The sample code included with this post contains a View Model with three properties, as listed:
Indeterminate, a Boolean that provides theIsIndeterminatevalue of theProgressIndicator.Progress: a double that is the source property of theValueproperty of theProgressIndicator. This takes effect when theProgressIndicator.IsIndeterminateproperty istrue.Message: a string value displayed via theProgressIndicator.
The page is bound to an instance of the MainPageViewModel. The ProgressIndicatorProxy binds to the three ViewModel properties. In addition, a ToggleSwitch is used to control the indeterminate state of the ProgressIndicator via the Indeterminate property in the ViewModel, and a Slider controls the ProgressIndicator's Value property in the same manner. See the following excerpt:
<u:ProgressIndicatorProxy IsIndeterminate="{Binding Indeterminate}"
Text="{Binding Message}"
Value="{Binding Progress}" />
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<toolkit:ToggleSwitch
IsChecked="{Binding Indeterminate, Mode=TwoWay}"
Header="Indeterminate" />
<Slider Value="{Binding Progress, Mode=TwoWay}"
Maximum="1" LargeChange=".2" />
</StackPanel>
</Grid>
The sample page is shown in Figure 1.

Note that there is no requirement to use the MVVM infrastructure located in the sample. And that the ProgressIndicatorProxy is entirely independent. I will, however, be releasing Calcium for Windows Phone 7 soon, which contains a cavalcade of useful components for building MVVM apps for WP7.
The custom ProgressIndicatorProxy provides a simple way to harness the new ProgressIndicator from your XAML. I hope you find it useful.
If you are interested in up-to-the-minute WP7 info, check out the Windows Phone Experts group on LinkedIn.
Post Comment
tsqcS0 Thanks a bunch for sharing this with all of us you actually know what you're talking about! Bookmarked. Please also visit my web site =). We could have a link exchange contract between us!
SsjAeS This web site is known as a stroll-by for all the information you wished about this and didn't know who to ask. Glimpse right here, and you'll definitely uncover it.
1IbG3h Really enjoyed this article post. Really Great.
b1apO0 I think this is a real great article post.Much thanks again. Really Great.
CeiRFJ Fantastic blog article.Really looking forward to read more. Really Great.
