As a quick introduction to the purpose of this and some future blog posts, I have received many emails and comments on YouTube videos from other students and developers around the world asking questions on how to implement features into their Windows Phone apps. While I thought it was great to give the quick answer to these folks, I thought I would also share some of the questions asked and the answers here on my blog to help out others too!

Q: How do you add a single instance of a progress indicator to a Windows Phone 8.1 Silverlight app so I can use it in all of my views?

The implementation for this is rather simple by taking advantage of the data binding model of building Windows Phone applications. By implementing a ProgressIndicator into a view model, it is possible to bind to it as a property through the SystemTray in the XAML of your views.

If you are using data binding in your application and have a view model, e.g. MainViewModel.cs, then open it up and we will add a new ProgressIndicator property to it. Otherwise, create a class in your solution and give it a sensible name like MainViewModel.

Setting up the view model for data binding

If you already have a MainViewModel set up with data binding, you can skip to the next section although it wouldn’t hurt to stick around.

Now that you have your MainViewModel class created, make sure to make it public so we can use it. The next task is to inherit the INotifyPropertyChanged interface. The interface has an event handler which you can use to notify your current view that a property has changed which will update any elements that are binding to it. Here is what this will look like:


public class MainViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged; 
}
To actually notify the app that properties have been changed, we will need to add a method that will be called when the property changes. This can be implemented as follows:

[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    var handler = this.PropertyChanged;
    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}

The CallerMemberName attribute in the parameter for the propertyName string allows us to get the name of the property and use that to notify that the property has been changed meaning that we can call OnPropertyChanged() from within the setter of the property and it will automatically use the name of the property as the propertyName parameter.

Now we are all set to start binding properties within the MainViewModel!

Creating the ProgressIndicator property

Here is the easy part! This is where we will hold the single instance of our ProgressIndicator so that it can be used globally across the application.

We first want to create a private variable of the ProgressIndicator. This is to allow us to call our OnPropertyChanged method within the property. Which leads onto, we now want to create a ProgressIndicator property which has get and set accessors. The get accessor should return the private variable, while our set accessor needs a bit more functionality. It should look as follows:


private ProgressIndicator progressIndicator;

public ProgressIndicator ProgressIndicator
{
    get
    {
        return this.progressIndicator;
    }
    set
    {
        if (value == this.progressIndicator)
        {
            return;
        }

        this.progressIndicator = value;
        this.OnPropertyChanged();
    }
}
In our set accessor, the reason that we are checking if the value is the same as the current property is that we don’t want to be setting the value and refreshing the UI if we have no need to. If the values aren’t equal however, we want to set the private variable to be the new value and notify the UI that the property has been changed. This will then let all UI elements that are bound to the property that it has changed and they will update themselves so. We now have a bindable property which we can use in our XAML!

Setting up the MainViewModel for global access

Now that we have our MainViewModel and our property for the ProgressIndicator setup, we need to create an instance of the MainViewModel that is globally accessible. As the App.xaml.cs is our main entry point for the application, it makes sense to create our instance there as a static property. As we will only need to have read access to the view model itself, we will only get it a get accessor.

Like before, we want to create a new private variable and public property of our MainViewModel. This should look as follows:


private static MainViewModel viewModel;

public static MainViewModel ViewModel
{
    get
    {
        return viewModel ?? (viewModel = new MainViewModel());
    }
}
The reason for making it static is so that we can use the view model from anywhere in our code just by calling App.ViewModel. For data binding sanity reasons, I also add the MainViewModel to the application’s main resource dictionary in the App.xaml file. You can do this as follows:

<ResourceDictionary>            
    <viewmodels:MainViewModel x:Key="MainViewModel" />
</ResourceDictionary>
You will need to add the value of xmlns:viewModels to reflect the namespace location of your MainViewModel, for example: xmlns:viewModels=”clr-namespace:DemoApp.ViewModels”. You’re now set to start binding!

Binding your ProgressIndicator to your XAML

Here is where all the magic happens. Open up any of the XAML views you want to use your new ProgressIndicator with and within the opening tag for your XAML add the following line to link your SystemTray to your ProgressIndicator:


xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
DataContext="{StaticResource MainViewModel}"
shell:SystemTray.IsVisible="True" shell:SystemTray.ProgressIndicator="{Binding ProgressIndicator}"
As the SystemTray is in the Microsoft.Phone.Shell namespace, we need to create the reference to it in order to use it. We then set up the DataContext with a static resource which is our MainViewModel. This static resource is picked up from the XAML Resource Dictionary we modified in the App.xaml file. Finally, we set the SystemTray visibility to true and bind our ProgressIndicator property to the SystemTray ProgressIndicator. Again for sanity reasons, open the CS file for your current view you are modifying, and add the following line of code in the constructor after the initialisation:

DataContext = App.ViewModel;
We have now covered all bases for binding our ProgressIndicator. Now from any place in code across your application, you can call something like:

var indicator = new ProgressIndicator {
    indicator.Text = "Some message",
    indicator.IsIndeterminate = true,
    indicator.IsVisible = true
};

App.ViewModel.ProgressIndicator = indicator;
If you’re on a view in your app that has the SystemTray ProgressIndicator bound to the MainViewModel ProgressIndicator, you will then notice it update and refresh with the data your provided! This will look like this:

Picstra ProgressIndicator Example

Picstra ProgressIndicator Example

Just follow the steps for binding to add the progress indicator to more pages in your application. I hope this helps! If you have any questions or want to request a how to, feel free to comment below or send me an email and I will be happy to help! If you also have a better solution, please feel free to let folks know in the comments too.

Join the discussion 4 Comments

Leave a Reply