Это последний фрагмент моего учебного пособия, в котором описан способ загрузки файлов в Dropbox из приложения Windows Phone. Ядро в значительной степени завершено прямо сейчас, и все, что нужно сделать, это правильно обработать фактический процесс загрузки (читай: убедитесь, что пользователь знает, что происходит). Вот некоторые подробности о дополнениях, которые я сделал в существующем каркасе приложения.
Прежде всего, я добавил новый класс, названный UploadCounter. Это специально предназначено для подсчета количества ожидающих загрузок.
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)); } } }
Обратите внимание, что класс реализует интерфейс INotifyPropertyChanged — таким образом, я могу связать его в любом месте приложения, и всякий раз, когда я изменяю значение свойства Counter, он автоматически связывается и результат обновляется в представлении (UI).
Мне нужно будет получить доступ к счетчику глобально (из любой точки приложения), поэтому я добавляю экземпляр UploadCounter к самому классу приложения:
Обратите внимание, что я также инициализирую этот класс при запуске приложения (посмотрите на конструктор). Одна вещь, которую вы, возможно, также заметили, это Диспетчер. Это не инициализируется здесь, а скорее на главной странице. Я собираюсь использовать его для обновления UploadCounter.Counter из вторичного потока позже, но я буду использовать диспетчер, связанный с потоком пользовательского интерфейса.
Тем не менее, в файле MainPage.cs, в конструкторе страниц у меня есть назначение Dispatcher:
Вернемся, однако, к самому свойству Counter. Как только я начинаю процесс загрузки, я устанавливаю для свойства количество элементов в списке изображений:
С каждой загрузкой, которая будет завершена, значение будет уменьшаться. Для этого мне нужно вернуться к классу OAuthClient и уменьшить счетчик при вызове GetResponse (метод, который обрабатывает конечный ответ при загрузке изображения):
Вот где в игру вступает диспетчер, о котором я говорил ранее. Если я не уменьшаю свойство с помощью диспетчера, будет вызван недопустимый межпотоковый вызов, и это вызовет исключение, поэтому, как правило, здесь рекомендуется использовать основной экземпляр Dispatcher.
Теперь, когда сам счетчик определил основной рабочий процесс, пришло время показать его где-нибудь. На момент загрузки я решил отобразить всплывающее окно и показать, сколько элементов ожидают в очереди. Я создал пользовательский элемент управления, который будет добавлен в качестве дочернего элемента в базовое всплывающее окно:
<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 — это экземпляр TextBlock, где я буду отображать количество оставшихся элементов. Я устанавливаю его привязку в коде после загрузки элемента управления:
Binding binding = new Binding(); binding.Source = App.uploadCounter; binding.Path = new PropertyPath("Counter"); binding.Converter = new IntToStringConverter(); RemainingText.SetBinding(TextBlock.TextProperty, binding);
Конвертер, который я использую здесь, является еще одним пользовательским классом, который я создал для преобразования целочисленных значений в строки и обратно.
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); } }
Когда начинается загрузка, я вручную создаю экземпляр Popup:
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);
Здесь следует заметить, что его свойство IsOpen привязано к Counter. Вы можете задаться вопросом — как целочисленное свойство может быть связано с логическим. Здесь используется конвертер, который всегда будет возвращать истину (всплывающее окно видно), если значение счетчика больше нуля (файлы все еще загружаются), и ложь, если значение счетчика равно нулю.
Конечный результат выглядит так:
В этом проекте еще предстоит проделать большую работу. Например, мне нужно проверить ответ, полученный от сервера после завершения загрузки — если это не {«result»: «winner!»}, Значит, что-то пошло не так. Кроме того, мне нужно будет реализовать функцию отмены, которая позволит пользователю отступать после того, как загрузка уже началась.
Проект с открытым исходным кодом и будет доступен в ближайшее время на его странице CodePlex .