Partager via


A Simple BackgroundDownloader driven User Control Implementation for Windows Store Apps

This post demonstrates a very simple user control implementation that displays a ringtone name and has a download button upon clicking which the relative MP3 file begins downloading. As downloading begins, the button is disabled and relative progress bar visibility is shown using a custom dependency property. The control makes use of BackgroundDownloader class for downloading file in the background. The downloaded file is by default saved in Music library and as the download progresses, the progress bar updates progress using a custom exposed Dependency Property. Here's how the user control bound in GridView looks like in sample app implemtnation,

To begin with, here's our POCO representing a ring tone,

 public class Ringtone
 {
 public string Title
 {
 get;
 set;
 }
 
 public string Path
 {
 get;
 set;
 }
 
 }

In the user control (Downloader.xaml.cs) you can find two dependency properties; IsDownloadInProgress that is used to control the visibility of progress bar and DownloadProgress, a double value to represent download percentage as bytes are received,

  public Visibility IsDownloadInProgress
 {
 get { return (Visibility)GetValue(IsDownloadInProgressProperty); }
 set { SetValue(IsDownloadInProgressProperty, value); }
 }
 
 // Using a DependencyProperty as the backing store for IsDownloadInProgress. This enables animation, styling, binding, etc...
 public static readonly DependencyProperty IsDownloadInProgressProperty =
 DependencyProperty.Register("IsDownloadInProgress", typeof(bool), typeof(Downloader), new PropertyMetadata(Visibility.Collapsed));
 
 public double DownloadProgress
 {
 get { return (double)GetValue(DownloadProgressProperty); }
 set { SetValue(DownloadProgressProperty, value); }
 }
 
 // Using a DependencyProperty as the backing store for DownloadProgress. This enables animation, styling, binding, etc...
 public static readonly DependencyProperty DownloadProgressProperty =
 DependencyProperty.Register("DownloadProgress", typeof(double), typeof(Downloader), new PropertyMetadata(0));

Above two dependency properties are bound with progress bar control as follows,

  <StackPanel>
 <TextBlock Margin="20" Style="{StaticResource SubheaderTextBlockStyle}" Text="{Binding Title}"></TextBlock>
 <Button Margin="20" Tag="{Binding Path}" Name="Button1" Click="Button_Click">Download</Button>
 <ProgressBar Name="Progressbar1" Margin="20" Visibility="{Binding IsDownloadInProgress}" Minimum="0" Maximum="100" Value="{Binding DownloadProgress}"></ProgressBar>
 </StackPanel>

Note that in the constructor of the user control (Downloader.xaml.cs), we've explicitly set the data context of progress bar to this, referring that its bound properties are exposed within the very user control.

 public Downloader()
 {
 this.InitializeComponent();
 
 //This will ensure that only progress bare makes use of depdnency property
 //otherwise Ringtone Title won't be displayed in the Text Block.
 Progressbar1.DataContext = this;
 }

Here’s how downloading is performed once button is clicked (file in stored in MusicLibrary folder by default and thus the corresponding capability is explicitly checked in manifest file). Also note that existing file is overridden,

  private async void Button_Click(object sender, RoutedEventArgs e)
 {
 Button button = (Button)sender;
 string path = button.Tag.ToString();
 string name = path.Substring(path.LastIndexOf('/') + 1);
 
 IsDownloadInProgress = Visibility.Visible;
 button.IsEnabled = false;
 
 BackgroundDownloader downloader = new BackgroundDownloader();
 StorageFile file = await KnownFolders.MusicLibrary.CreateFileAsync(name,CreationCollisionOption.ReplaceExisting);
 DownloadOperation operation = downloader.CreateDownload(new Uri(path, UriKind.Absolute), file);
 Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>();
 progressCallback.ProgressChanged += progressCallback_ProgressChanged;
 
 await operation.StartAsync().AsTask(progressCallback);
 }

And here’s the progress response callback handler that sets progress bar value and hides progress bar as downloading is complete. Note that if we would have not used dependency property (DownloadProgress & IsDownloadInProgress), we were supposed to make use of INotifyPropertyChanged. That’s one of the many advantages of DependencyProeprty that it avoids need of INotifyPropertyChanged.

 void progressCallback_ProgressChanged(object sender, DownloadOperation e)
 {
 try
 {
 double bytesRecieved = Convert.ToDouble(e.Progress.BytesReceived);
 double totalBytesToReceive = Convert.ToDouble(e.Progress.TotalBytesToReceive);
 DownloadProgress = (bytesRecieved / totalBytesToReceive) * 100;
 
 if (DownloadProgress == 100)
 {
 IsDownloadInProgress = Windows.UI.Xaml.Visibility.Collapsed;
 Button1.IsEnabled = true;
 }
 }
 catch (Exception)
 {
 throw;
 }
 }

The sample implementation is attached. For simplicity of purpose, the Urls of ringtones are hardcoded in the app. Note that if the progress bar doesn’t yield progress for you, try changing path of MP3 to a larger file.

Happy Coding :)

Ringtone Downloader.zip

Comments

  • Anonymous
    July 26, 2017
    Nice one... works (Y)