суббота, 9 июня 2012 г.

Использоване окна выбора файлов в Windows 8 приложениях

В прошлый раз, мы с вами посмотрели, как работать с файлами напрямую. Но очень часто, на приходится попросить пользователя выбрать некоторый файл. Т.к. Metro Style приложения ориентированы на "страницы", а не "окна", то с диалогами в них тяжело. Вместо привычного OpenFileDialog придется использовать FileOpenPicker. Именно о нем, мы сегодня и поговорим.


 Для примера давайте сделаем приложение, которое будет загружать в список выбранные пользователем картинки. Давайте создадим Metro Style приложение. Т.к. мы планируем работать с файлами, то наше приложение должно запросить при старте права на доступ к директории "Изображения" пользователя. Как это сделать, можно прочитать здесь, только можно не указывать к файлам каких расширений нам нужен доступ. Считается, что в папке изображений все равно кроме изображений ничего не будет.
Давайте сформируем разметку главной страницы приложения:

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition Height="1*" />
    Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <Button x:Name="btAddOnePicture" Content="Добавить одно изображение" Click="btAddOnePicture_Click_1" />
        <Button x:Name="btAddSomePicture" Content="Добавить несколько изображений" Click="btAddSomePicture_Click_1" />
    StackPanel>
    <ListBox x:Name="lbPictures" Grid.Row="1">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Image MaxWidth="100" Source="{Binding}" />
            DataTemplate>
        ListBox.ItemTemplate>
    ListBox>
Grid>

Первый пример, на то, как выбрать одиночное изображение. Собственно, здесь будет сразу много всего, но разбивать на части особого смысла не вижу, т.к. маловероятно, что придется пользоваться этим всем по отдельности. Итак, добавляем на страницу поле, для хранения изображений:

ObservableCollection<BitmapImage> pictures = new ObservableCollection<BitmapImage>();

Например в конструкторе, помещаем наш список в качестве источника элементов для списка:

lbPictures.ItemsSource = pictures;

Ну и вот так, мы можем загрузить одиночные картинки в список:
private async void btAddOnePicture_Click_1(object sender, RoutedEventArgs e)
{
    FileOpenPicker openPicker = new FileOpenPicker();
    // Выбираем способ отображения
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    // Выбираем с какой папки начинать
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    // Ну и фильтр по расширениям
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");
    // Показываем страницу выбора одиночного файла
    StorageFile pictureFile = await openPicker.PickSingleFileAsync();
    if (pictureFile != null)
    {
        BitmapImage bitmapImage = new BitmapImage();
        bitmapImage.SetSource(await pictureFile.OpenReadAsync());
        pictures.Add(bitmapImage);
    }
}
Запускаем приложение:
Нажимаем кнопку и видим страницу выбора файла:
Выбираем файл, нажимаем открыть:
Все работает.
Вторая кнопка в окне, предназначена для демонстрации второго пример, на множественный выбор файлов. На самом деле все очень похоже на одиночный, только вызываем другой метод и получаем не один файл а коллекцию. Вот так может выглядеть обработчик для второй кнопки:

private async void btAddSomePicture_Click_1(object sender, RoutedEventArgs e)
{
    FileOpenPicker openPicker = new FileOpenPicker();
    // Выбираем способ оторбражения
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    // Выбираем с какой папки начинать
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    // Ну и фильтр по расширениям
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");
    // Показываем страницу выбора одиночного файла
    IReadOnlyList<StorageFile> pictureFiles = await openPicker.PickMultipleFilesAsync();
    if (pictureFiles != null)
    {
        foreach (var pictureFile in pictureFiles)
        {
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.SetSource(await pictureFile.OpenReadAsync());
            pictures.Add(bitmapImage);
        }
    }
}

Картинки с запуском приводить не буду, т.к. они кроме второй (можно выбрать несколько файлов) отличатся от первого примера не будут.
В третьем примере, рассмотрим диалог для сохранения файла. Вполне логично, что класс реализующий выбор файла для сохранения будет называться SaveFilePicker. Давайте будем выбирать файл при помощи OpenFilePicker и перемещать/переименовывать его.
Добавляем на страницу еще одну кнопку вот с таким обработчиком:

private async void btSaveSelectedImage_Click_1(object sender, RoutedEventArgs e)
{
    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    openPicker.FileTypeFilter.Add(".jpg");
    StorageFile pictureFile = await openPicker.PickSingleFileAsync();
    if (pictureFile != null)
    {
        FileSavePicker savePicker = new FileSavePicker();
        savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
        // Указываем какие типы файлов для сохранения может выбрать пользователь
        savePicker.FileTypeChoices.Add("Jpeg", new List<string>() { ".jpg" });
        // Значение по умолчанию для имени файла
        savePicker.SuggestedFileName = pictureFile.Name;
        StorageFile distinationFile = await savePicker.PickSaveFileAsync();
        if (distinationFile != null)
        {
            await pictureFile.MoveAndReplaceAsync(distinationFile);
        }
    }
}

Все, выбираем файл, меняем ему имя и проверяем через проводник, что файл переименовался.
Последний, четвертый пример, на выбор папки. Решим задачу аналогичную третьему примеру, только файл будем не перемещать/переименовывать, а копировать в выбранную папку.
Добавляем еще одну кнопку и пишем у нее вот такой обработчик:

private async void btCopySelectedImage_Click_1(object sender, RoutedEventArgs e)
{
    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    openPicker.FileTypeFilter.Add(".jpg");
    StorageFile pictureFile = await openPicker.PickSingleFileAsync();
    if (pictureFile != null)
    {
        FolderPicker folderPicker = new FolderPicker();
        // Обратите внимание на целевую папку
        folderPicker.SuggestedStartLocation = PickerLocationId.Desktop;
        folderPicker.FileTypeFilter.Add(".jpg");
        StorageFolder folder = await folderPicker.PickSingleFolderAsync();
        if (folder != null)
        {
            await pictureFile.CopyAsync(folder);
        }
    }
}
Все, теперь мы можем, запустив приложение, выбрать изображение и скопировать его в заданную папку. Обратите внимание, что по умолчанию для сохранения откроется рабочий стол:
И мало того, что он откроется, мы можем прямо здесь нажать "Выбрать эту папку" и изображение сохранится в нее. Как вы считаете, если я заказывал доступ только к папке "Изображения", почему так происходит?

На сегодня на этом все. Благодаря этим примерам и примерам рассмотренным в предыдущей статье, у нас теперь есть весь функционал для работы с файлами.

Комментариев нет:

Отправить комментарий