Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Developing SevenDrops - A Dropbox-based photo uploader for Windows Phone 7 [6/6]

DZone's Guide to

Developing SevenDrops - A Dropbox-based photo uploader for Windows Phone 7 [6/6]

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

This is the last piece of my tutorial set that describes the way to upload files to Dropbox from a Windows Phone application. The core is pretty much completed right now and all that needs to be done is to properly handle the actual upload process (read: make sure the user knows what's going on). Here are some details on the additions I made to the existing application skeleton. 

First of all, I added a new class, called UploadCounter. This is specifically dedicated to counting the number of currently pending uploads.

public class UploadCounter : INotifyPropertyChanged
{
    private int counter = 0;
    public int Counter
    {
        get
        {
            return counter;
        }
        set
        {
            if (value != counter)
            {
                counter = value;
                RaisePropertyChange("Counter");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChange(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Notice that the class implements the INotifyPropertyChanged interface - this way I can bind it anywhere in the application and whenever I change the value of the Counter property, it will be automatically re-bound and the result updated in the View (UI).

I will need to access the counter globally (from anywhere in the app), so I am adding an instance of UploadCounter to the App class itself:

Notice that I am also initializing this class when the application starts (look at the constructor). One thing you might've also noticed here is the Dispatcher. It is not initialized here but rather in the main page. I am going to use it to update the UploadCounter.Counter from a secondary thread later on, but I will be using the dispatcher associated with the UI thread.

That being said, in the MainPage.cs file, in the page constructor I have the Dispatcher assignment:

Let's get back to the Counter property itself, though. Once I start the upload process, I am setting the property to the number of items in the image list:

With each download that will be completed, the value will be decremented. In order to do this, I have to go back to the OAuthClient class and decrement the counter when GetResponse is invoked (the method that handles the end response when a picture is uploaded):

Here is where the dispatcher I mentioned before comes into play. If I am not decrementing the property via a dispatcher, an invalid cross-thread call will be triggered and that will cause an exception, so it is generally a good idea to use the main Dispatcher instance here.

Now that the counter itself has the basic workflow defined, it is time to show it somewhere. For the time of the upload, I decided to display a Popup and show how many items are pending in the queue. I created a custom user control that will be added as a child to a base Popup:

<UserControl x:Class="SevenDrops.Helpers.UploadingFiles"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    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}"
    Loaded="UserControl_Loaded"
    d:DesignHeight="221" d:DesignWidth="256">
    
    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}" Height="219" Width="261">
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBlock1" Text="Uploading files..." VerticalAlignment="Top" Width="239" />
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,177,0,0" Name="textBlock2" Text="Remaining files:" VerticalAlignment="Top" />
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="157,177,0,0" x:Name="RemainingText" VerticalAlignment="Top" />
    </Grid>
</UserControl>

RemainingText is the TextBlock instance where I will display the number of remaining items. I am setting its binding in the code-behind, once the control loads:

Binding binding = new Binding();
binding.Source = App.uploadCounter;
binding.Path = new PropertyPath("Counter");
binding.Converter = new IntToStringConverter();

RemainingText.SetBinding(TextBlock.TextProperty, binding);

The converter I am using here is another custom class I created to convert integer values to strings and back.

public class IntToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return System.Convert.ToString(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return System.Convert.ToInt32(value);
    }
}

When the upload starts, I am manually building the Popup instance:

Popup uploadPopup = new Popup();
uploadPopup.Child = new UploadingFiles();
uploadPopup.IsOpen = true;
uploadPopup.VerticalOffset = 100;
uploadPopup.HorizontalOffset = 25;

Binding b = new Binding();
b.Source = App.uploadCounter;
b.Converter = new CounterToVisibilityConverter();
b.Path = new PropertyPath("Counter");
uploadPopup.SetBinding(Popup.IsOpenProperty, b);

One thing to notice here is that its IsOpen property is bound to the Counter. You might be wondering - how an integer property can be bound to a boolean one. There is a converter used here that will always return true (the Popup is visible) if the value of the Counter is bigger than zero (files are still uploading) and false if the Counter value is zero.

The end-result looks like this:

There is still more work to be done on the current project. For example, I need to check for the response received from the server on upload completion - if it is not {"result": "winner!"} then something went wrong. Also, I would need to implement a Cancel feature that will allow the user to back down after the upload already started.

The project is open-source and will be available shortly on its CodePlex page.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}