Статьи

Создание клиента Imgur для Windows Phone — Часть 6 — Загрузка пользовательского интерфейса

Если вы пропустили предыдущие четыре части, вы можете легко найти их здесь:

В предыдущей статье я говорил о создании механизма загрузки. Теперь я собираюсь поговорить о создании рабочего процесса пользовательского интерфейса, необходимого для создания удобной процедуры загрузки.

Я создаю новую страницу загрузки ( UploadPage.xaml ), которая позволяет пользователю выбрать изображение из библиотеки мультимедиа, а также при необходимости создать новую. Не только это, но я также даю пользователю возможность ввести название и описание изображения, даже если они не являются обязательными.

Полный XAML выглядит так:

<phone:PhoneApplicationPage
    x:Class="Imagine.UploadPage"
    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"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
    shell:SystemTray.IsVisible="False">

    <!--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>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="UPLOAD IMAGE" Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="230"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            
            <Image Stretch="UniformToFill" x:Name="imgPreview" Margin="12,12,12,12"></Image>
            
            <Button x:Name="btnPick" Click="btnPick_Click_1">
                <Image Source="/Images/photocapture.png"></Image>
            </Button>
            
            <StackPanel Grid.Row="1">
                <TextBlock Style="{StaticResource PhoneTextTitle3Style}">Name:</TextBlock>
                <TextBox x:Name="txtName"></TextBox>
                <TextBlock Style="{StaticResource PhoneTextTitle3Style}">Description:</TextBlock>
                <TextBox x:Name="txtDescription" TextWrapping="Wrap" AcceptsReturn="True" 
                         TextOptions.TextHintingMode="Animated" Height="210"></TextBox>
            </StackPanel>
        </Grid>
        
        <Grid Visibility="Collapsed" Grid.RowSpan="2" x:Name="grdUploading">
            <Grid.Background>
                <SolidColorBrush Color="Black"></SolidColorBrush>
            </Grid.Background>
            
            <TextBlock Text="Uploading..." HorizontalAlignment="Center"
                       VerticalAlignment="Center"></TextBlock>

            <toolkit:PerformanceProgressBar IsIndeterminate="True" Margin="0,80,0,0"></toolkit:PerformanceProgressBar>
        </Grid>
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar>
            <shell:ApplicationBarIconButton x:Name="btnUpload" Click="btnUpload_Click_1" Text="ok" IconUri="/Images/appbar.check.png"></shell:ApplicationBarIconButton>
            <shell:ApplicationBarIconButton x:Name="btnCancel" Click="btnCancel_Click_1" Text="cancel" IconUri="/Images/appbar.cancel.png"></shell:ApplicationBarIconButton>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
</phone:PhoneApplicationPage>

Чтобы сделать краткий обзор, вот как это выглядит в результате:

Основная рабочая сетка разделена на две части — компонент предварительного просмотра изображения,  поверх которого расположен элемент  управления Button , и мета-область, предназначенная для указания имени и описания загружаемого изображения. 

Элемент   управления изображением за кнопкой будет отображать выбранный контент. В то же время основной фон сетки (для LayoutRoot ) также будет отображать выбранное изображение, хотя и в гораздо большем формате. Все это делается с помощью  PhotoChooserTask :

PhotoChooserTask task = new PhotoChooserTask() { ShowCamera = true };
task.Completed += (s, d) =>
    {
        if (d.TaskResult == TaskResult.OK)
        {
            byte[] buffer = new byte[16 * 1024];

            using (MemoryStream stream = new MemoryStream())
            {
                int read = 0;

                while ((read = d.ChosenPhoto.Read(buffer, 0, buffer.Length)) > 0)
                {
                    stream.Write(buffer, 0, read);
                }

                BitmapImage image = new BitmapImage();
                image.SetSource(stream);

                imgPreview.Source = image;

                ImageBrush brush = new ImageBrush();
                brush.ImageSource = image;
                LayoutRoot.Background = brush;
                brush.Opacity = .2;
                brush.Stretch = Stretch.UniformToFill;

                ImageContent = stream.ToArray();
            }
        }
    };
task.Show();

ImageContent — это общий байтовый буфер, который будет использоваться, если пользователь хочет загрузить выбранное изображение. Как только выбор сделан, пользовательский интерфейс будет выглядеть так:

Вот фрагмент кода, который активирует загрузку:

grdUploading.Visibility = System.Windows.Visibility.Visible;
this.ApplicationBar.IsVisible = false;

App.ServiceClient.UploadImage(ImageContent, txtName.Text, txtDescription.Text, (n, image) =>
    {
        if (n)
        {
            Dispatcher.BeginInvoke(() =>
            {
                Clipboard.SetText(image.Image.Link);

                MessageBox.Show("Your image was uploaded. The link is placed in the clipboard.",
                    "Image Upload", MessageBoxButton.OK);

                if (NavigationService.CanGoBack)
                    NavigationService.GoBack();
            });
        }
        else
        {
            Dispatcher.BeginInvoke(() =>
                {
                    MessageBox.Show("There was an error uploading the image. Please try again later.",
                        "Image Upload", MessageBoxButton.OK);
                });
        }

        Dispatcher.BeginInvoke(() =>
                {
                    grdUploading.Visibility = System.Windows.Visibility.Collapsed;
                    this.ApplicationBar.IsVisible = true;
                });
    });

Когда пользователи принимают изображение, наложение блокирует весь пользовательский интерфейс, чтобы показать, что идет загрузка:

Настраиваемое действие, которое передается в UploadImage, будет вызвано двумя аргументами — логическим флагом, показывающим, была ли загрузка успешной или нет, и десериализованным экземпляром ImgurAtomicImageData . Если первый аргумент равен true, тогда я устанавливаю URL изображения в буфер обмена, чтобы пользователь мог поделиться им при необходимости. Если загрузка не удалась, пользователю сообщают об этом. 

Вы можете скачать текущий исходный код проекта  здесь . Не забудьте указать свой ключ API и секрет.