How to Display Activity Progress in Windows Phone Applications

Introduction

Certain type of operations in mobile applications take time. For good customer experience, it is suggested that the user be informed that the activity is in progress. Providing such an indication helps prevents users from guessing whether their action was registered with the application or not.

Displaying activity progress also allows a user to visualize how long it will take for the task to complete.

Windows Phone enables displaying activity progress via controls like ProgressIndicator.

The ProgressIndicator class resides in the Microsoft.Phone.Shell namespace in the Microsoft.Phone.dll assembly.

The control can be declared in XAML as shown below:

<ProgressIndicator .../>

Note that the ProgressIndicator is visible in the status bar, but unlike desktop applications, the status bar is at the very top of the phone screen (next to where one would find the battery icon and the phone signal icon.

ProgressIndicator comes in two variants: determinate and indeterminate. If the IsIndeterminate property value is set to true, the progress indicator will only display “…….” to indicate progress of the activity.

To display the progress indicator on a XAML page, we need to specify the instance of the ProgressIndicator class as one of the properties on the SystemTray’s SetProgressIndicator API.

Hands-On

Let us build a simple Windows Phone application that demonstrates how to display activity progress using ProgressIndicator. We’ll call this project WPProgressIndicatorDemo.

New Project
New Project

We’ll add a TextBlock on the MainPage as well as a button. In our demo application, we will start a long running activity on the click of the button and indicate completion of the activity using the TextBlock. While the activity is in progress, we will use ProgressIndicator to indicate.

After adding the two controls, our XAML is shown below.

<phone:PhoneApplicationPage
    x:Class="WPProgressIndicatorDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
 
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!-- LOCALIZATION NOTE:
            To localize the displayed strings copy their values to appropriately named
            keys in the app's neutral language resource file (AppResources.resx) then
            replace the hard-coded text value between the attributes' quotation marks
            with the binding clause whose path points to that string name.
 
            For example:
 
                Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}"
 
            This binding points to the template's string resource named "ApplicationTitle".
 
            Adding supported languages in the Project Properties tab will create a
            new resx file per language that can carry the translated values of your
            UI strings. The binding in these examples will cause the value of the
            attributes to be drawn from the .resx file that matches the
            CurrentUICulture of the app at run time.
         -->
 
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Button x:Name="buttonStart" Content="Button" HorizontalAlignment="Left" Margin="167,140,0,0" VerticalAlignment="Top" />
            <TextBlock x:Name="textBlockStatus" HorizontalAlignment="Left" Margin="115,81,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/>
        </Grid>
 
        <!--Uncomment to see an alignment grid to help ensure your controls are
            aligned on common boundaries.  The image has a top margin of -32px to
            account for the System Tray. Set this to 0 (or remove the margin altogether)
            if the System Tray is hidden.
 
            Before shipping remove this XAML and the image itself.-->
        <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" Grid.RowSpan="2" IsHitTestVisible="False" />-->
    </Grid>
 
</phone:PhoneApplicationPage>

Now, we will add a click event handler for the button. In this method, we will create an instance of the ProgressIndicator class and specify it as indeterminate and set the progress indicator of the system tray to the instance.

private void buttonStart_Click(object sender, RoutedEventArgs e)
        {
            ProgressIndicator progressIndicator = new ProgressIndicator();
            progressIndicator.IsVisible = true;
            progressIndicator.IsIndeterminate = true;
            progressIndicator.Text = "Downloading...";
            SystemTray.SetProgressIndicator(this, progressIndicator);
 
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                textBlockStatus.Text = "Async runner started. Please wait...";
            });
 
            AsyncRunner(DateTime.Now);
 
            
        }

Note that in the above method, we used a delegate to update the UI thread, and also called an asynchronous runner method. This async runner method will create a new background worker object, which will do the work.

public void AsyncRunner(DateTime dumpDate)
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerAsync(dumpDate);
        }

The above method introduces two new methods we would need to implement – one which will be called when the worker completes the activity (we will use this to signal MainPage.xaml to update the TextBlock to say “Done”). The second method will actually do the hard work (in our case, looping over all the possible values from 0 to int.MaxValue.

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
 
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                textBlockStatus.Text = "Done.";
            });
 
            SystemTray.ProgressIndicator.IsVisible = false;
        }

Note that when the worker has completed the work, we set the progress indicator to become invisible.

private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();
            //Thread.Sleep(1000);
            for (int i = 0; i < int.MaxValue; i++) ;
                
            //Thread.Sleep(1000);
        }

The above code snippet is a representative of a time consuming task (For simplicities purpose, we are looping here.

Our demo is complete. If you run the application now, you will notice the following screenshots.

Task not started
Task not started

 

Task in progress
Task in progress

 

Task complete
Task complete

You can see how simple it is to display activity progress using the ProgressIndicator class.

You can download the sample code used in this walkthrough below.

Summary

In this article, we learned how to display activity progress using the ProgressIndicator class. I hope you have found this information useful.

About the Author

Vipul Patel is a Program Manager currently working at Amazon Corporation. He has formerly worked at Microsoft in the Lync team and in the .NET team (in the Base Class libraries and the Debugging and Profiling team). He can be reached at vipul.patel@hotmail.com



Related Articles

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

Most Popular Programming Stories

More for Developers

RSS Feeds