Bagikan melalui


Mengimpor media dari perangkat

Artikel ini menjelaskan cara mengimpor media dari perangkat, termasuk mencari sumber media yang tersedia, mengimpor file seperti video, foto, dan file sespan, dan menghapus file yang diimpor dari perangkat sumber.

Catatan

Kode dalam artikel ini diadaptasi dari sampel aplikasi MediaImport UWP . Anda dapat mengkloning atau mengunduh sampel ini dari repositori Git sampel aplikasi Universal Windows untuk melihat kode dalam konteks atau menggunakannya sebagai titik awal untuk aplikasi Anda sendiri.

Membuat UI impor media sederhana

Contoh dalam artikel ini menggunakan UI minimal untuk mengaktifkan skenario impor media inti. Untuk melihat cara membuat UI yang lebih kuat untuk aplikasi impor media, lihat sampel MediaImport. XAML berikut membuat panel tumpukan dengan kontrol berikut:

  • Tombol untuk memulai pencarian sumber dari mana media dapat diimpor.
  • ComboBox untuk mencantumkan dan memilih dari sumber impor media yang ditemukan.
  • Kontrol ListView untuk ditampilkan dan dipilih dari item media dari sumber impor yang dipilih.
  • Tombol untuk memulai impor item media dari sumber yang dipilih.
  • Tombol untuk memulai penghapusan item yang telah diimpor dari sumber terpilih.
  • Tombol untuk membatalkan operasi impor media asinkron.
<StackPanel Orientation="Vertical">
    <Button x:Name="findSourcesButton" Click="findSourcesButton_Click" Content="Find sources"/>
    <ComboBox x:Name="sourcesComboBox" SelectionChanged="sourcesComboBox_SelectionChanged"/>
    <ListView x:Name="fileListView" 
                    HorizontalAlignment="Left" Margin="182,260,0,171" 
                    Width="715" 
                    SelectionMode="None" 
                    BorderBrush="#FF858585"   
                    BorderThickness="1" 
                    ScrollViewer.VerticalScrollBarVisibility="Visible">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="0.05*"/>
                        <ColumnDefinition Width="0.20*"/>
                        <ColumnDefinition Width="0.75*"/>
                    </Grid.ColumnDefinitions>
                    <CheckBox Grid.Column="0" IsChecked="{Binding ImportableItem.IsSelected, Mode=TwoWay}" />
                    <!-- Click="CheckBox_Click"/>-->
                    <Image Grid.Column="1" Source="{Binding Thumbnail}" Width="120" Height="120" Stretch="Uniform"/>
                    <TextBlock Grid.Column="2" Text="{Binding ImportableItem.Name}" VerticalAlignment="Center" Margin="10,0"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    
    <Button x:Name="importButton" Click="importButton_Click" Content="Import"/>
    <Button x:Name="deleteButton" Click="deleteButton_Click" Content="Delete"/>
    <Button x:Name="cancelButton" Click="cancelButton_Click" Content="Cancel"/>
    <ProgressBar x:Name="progressBar" SmallChange="0.01" LargeChange="0.1" Maximum="1"/>
    
</StackPanel>

Menyiapkan file code-behind Anda

Tambahkan menggunakan direktif untuk menyertakan namespace layanan yang digunakan oleh contoh ini yang belum disertakan dalam templat proyek default.

using Windows.Media.Import;
using System.Threading;
using Windows.UI.Core;
using System.Text;

Menyiapkan pembatalan tugas untuk operasi impor media

Karena operasi impor media dapat memakan waktu lama, operasi tersebut dilakukan secara asinkron menggunakan IAsyncOperationWithProgress. Nyatakan variabel anggota kelas jenis CancellationTokenSource yang akan digunakan untuk membatalkan operasi yang sedang berlangsung jika pengguna mengklik tombol batalkan.

CancellationTokenSource cts;

Terapkan handler untuk tombol batalkan. Contoh yang ditunjukkan nanti dalam artikel ini akan menginisialisasi CancellationTokenSource saat operasi dimulai dan mengaturnya ke null saat operasi selesai. Di handler tombol batal, periksa untuk melihat apakah token null, dan jika tidak, panggil Batal untuk membatalkan operasi.

private void cancelButton_Click(object sender, RoutedEventArgs e)
{
    if (cts != null)
    {
        cts.Cancel();
        System.Diagnostics.Debug.WriteLine("Operation canceled by the Cancel button.");
    }
}

Kelas pembantu pengikatan data

Dalam skenario impor media umum, Anda menampilkan daftar item media yang tersedia untuk diimpor kepada pengguna, mungkin ada sejumlah besar file media untuk dipilih dan, biasanya, Anda ingin menampilkan gambar mini untuk setiap item media. Untuk alasan ini, contoh ini menggunakan tiga kelas pembantu untuk memuat entri secara bertahap ke dalam kontrol ListView saat pengguna menggulir ke bawah melalui daftar.

Kelas-kelas ini disediakan dalam sampel MediaImport dan dapat ditambahkan ke proyek Anda tanpa modifikasi. Setelah menambahkan kelas pembantu ke proyek Anda, deklarasikan variabel anggota kelas jenis GeneratorIncrementalLoadingClass yang akan digunakan nanti dalam contoh ini.

GeneratorIncrementalLoadingClass<ImportableItemWrapper> itemsToImport = null;

Menemukan sumber yang tersedia dari mana media dapat diimpor

Di penangan klik untuk tombol temukan sumber, panggil metode statis PhotoImportManager.FindAllSourcesAsync untuk memulai sistem yang mencari perangkat tempat media dapat diimpor. Setelah menunggu penyelesaian operasi, ulangi setiap objek PhotoImportSource dalam daftar yang dikembalikan dan tambahkan entri ke ComboBox, atur properti Tag ke objek sumber itu sendiri sehingga dapat dengan mudah diambil ketika pengguna membuat pilihan.

private async void findSourcesButton_Click(object sender, RoutedEventArgs e)
{
    var sources = await PhotoImportManager.FindAllSourcesAsync();
    foreach (PhotoImportSource source in sources)
    {
        ComboBoxItem item = new ComboBoxItem();
        item.Content = source.DisplayName;
        item.Tag = source;
        sourcesComboBox.Items.Add(item);
    }
}

Deklarasikan variabel anggota kelas untuk menyimpan sumber impor yang dipilih pengguna.

PhotoImportSource importSource;

Di handler SelectionChanged untuk comboBox sumber impor, atur variabel anggota kelas ke sumber yang dipilih lalu panggil metode pembantu FindItems yang akan ditampilkan nanti di artikel ini.

private void sourcesComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    this.importSource = (PhotoImportSource)((ComboBoxItem)sourcesComboBox.SelectedItem).Tag;
    FindItems();
}

Temukan item yang akan diimpor

Tambahkan variabel anggota kelas jenis PhotoImportSession dan PhotoImportFindItemsResult yang akan digunakan dalam langkah-langkah berikut.

PhotoImportSession importSession;
PhotoImportFindItemsResult itemsResult;

Dalam metode FindItems, inisialisasi variabel CancellationTokenSource sehingga dapat digunakan untuk membatalkan operasi temukan jika perlu. Dalam blok coba, buat sesi impor baru dengan memanggil CreateImportSession pada objek PhotoImportSource yang dipilih oleh pengguna. Buat objek Kemajuan baru untuk menyediakan panggilan balik untuk menampilkan kemajuan operasi temukan. Selanjutnya, panggil FindItemsAsync untuk memulai operasi temukan. Berikan nilai PhotoImportContentTypeFilter untuk menentukan apakah foto, video, atau keduanya harus dikembalikan. Berikan nilai PhotoImportItemSelectionMode untuk menentukan apakah semua, tidak ada, atau hanya item media baru yang dikembalikan dengan properti IsSelected yang diatur ke true. Properti ini terikat ke kotak centang untuk setiap item media dalam templat item ListBox kami.

FindItemsAsync mengembalikan IAsyncOperationWithProgress. Metode ekstensi AsTask digunakan untuk membuat tugas yang dapat ditunggu, dapat dibatalkan dengan token pembatalan, dan yang melaporkan kemajuan menggunakan objek Kemajuan yang disediakan.

Selanjutnya kelas pembantu pengikatan data, GeneratorIncrementalLoadingClass diinisialisasi. FindItemsAsync, ketika kembali dari ditunggu, mengembalikan objek PhotoImportFindItemsResult . Objek ini berisi informasi status tentang operasi temukan, termasuk keberhasilan operasi dan jumlah berbagai jenis item media yang ditemukan. Properti FoundItems berisi daftar objek PhotoImportItem yang mewakili item media yang ditemukan. Konstruktor GeneratorIncrementalLoadingClass mengambil sebagai argumen jumlah total item yang akan dimuat secara bertahap, dan fungsi yang menghasilkan item baru untuk dimuat sesuai kebutuhan. Dalam hal ini, ekspresi lambda yang disediakan membuat instans baru importableItemWrapper yang membungkus PhotoImportItem dan menyertakan gambar mini untuk setiap item. Setelah kelas pemuatan bertahap diinisialisasi, atur ke properti ItemsSource kontrol ListView di UI. Sekarang, item media yang ditemukan akan dimuat secara bertahap dan ditampilkan dalam daftar.

Selanjutnya, informasi status operasi temukan adalah output. Aplikasi umum akan menampilkan informasi ini kepada pengguna di UI, tetapi contoh ini hanya menghasilkan informasi ke konsol debug. Terakhir, atur token pembatalan ke null karena operasi selesai.

private async void FindItems()
{
    this.cts = new CancellationTokenSource();

    try
    {
        this.importSession = this.importSource.CreateImportSession();

        // Progress handler for FindItemsAsync
        var progress = new Progress<uint>((result) =>
        {
            System.Diagnostics.Debug.WriteLine(String.Format("Found {0} Files", result.ToString()));
        });

        this.itemsResult =
            await this.importSession.FindItemsAsync(PhotoImportContentTypeFilter.ImagesAndVideos, PhotoImportItemSelectionMode.SelectAll)
            .AsTask(this.cts.Token, progress);

        // GeneratorIncrementalLoadingClass is used to incrementally load items in the Listview view including thumbnails
        this.itemsToImport = new GeneratorIncrementalLoadingClass<ImportableItemWrapper>(this.itemsResult.TotalCount,
        (int index) =>
        {
            return new ImportableItemWrapper(this.itemsResult.FoundItems[index]);
        });

        // Set the items source for the ListView control
        this.fileListView.ItemsSource = this.itemsToImport;

        // Log the find results
        if (this.itemsResult != null)
        {
            var findResultProperties = new System.Text.StringBuilder();
            findResultProperties.AppendLine(String.Format("Photos\t\t\t :  {0} \t\t Selected Photos\t\t:  {1}", itemsResult.PhotosCount, itemsResult.SelectedPhotosCount));
            findResultProperties.AppendLine(String.Format("Videos\t\t\t :  {0} \t\t Selected Videos\t\t:  {1}", itemsResult.VideosCount, itemsResult.SelectedVideosCount));
            findResultProperties.AppendLine(String.Format("SideCars\t\t :  {0} \t\t Selected Sidecars\t:  {1}", itemsResult.SidecarsCount, itemsResult.SelectedSidecarsCount));
            findResultProperties.AppendLine(String.Format("Siblings\t\t\t :  {0} \t\t Selected Sibilings\t:  {1} ", itemsResult.SiblingsCount, itemsResult.SelectedSiblingsCount));
            findResultProperties.AppendLine(String.Format("Total Items Items\t :  {0} \t\t Selected TotalCount \t:  {1}", itemsResult.TotalCount, itemsResult.SelectedTotalCount));
            System.Diagnostics.Debug.WriteLine(findResultProperties.ToString());
        }

        if (this.itemsResult.HasSucceeded)
        {
            // Update UI to indicate success
            System.Diagnostics.Debug.WriteLine("FindItemsAsync succeeded.");
        }
        else
        {
            // Update UI to indicate that the operation did not complete
            System.Diagnostics.Debug.WriteLine("FindItemsAsync did not succeed or was not completed.");
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Photo import find items operation failed. " + ex.Message);
    }


    this.cts = null;
}

Mengimpor item media

Sebelum menerapkan operasi impor, nyatakan objek PhotoImportImportItemsResult untuk menyimpan hasil operasi impor. Ini akan digunakan nanti untuk menghapus item media yang berhasil diimpor dari sumber.

private PhotoImportImportItemsResult importedResult;

Sebelum memulai operasi impor media, inisialisasi variabel CancellationTokenSource dan dengan mengatur nilai kontrol ProgressBar ke 0.

Jika tidak ada item yang dipilih dalam kontrol ListView , maka tidak ada yang bisa diimpor. Jika tidak, inisialisasi objek Kemajuan untuk memberikan panggilan balik kemajuan yang memperbarui nilai kontrol bilah kemajuan. Daftarkan handler untuk peristiwa ItemImported dari PhotoImportFindItemsResult yang dikembalikan oleh operasi temukan. Kejadian ini akan dinaikkan setiap kali item diimpor dan, dalam contoh ini, menghasilkan nama setiap file yang diimpor ke konsol debug.

Panggil ImportItemsAsync untuk memulai operasi impor. Sama seperti operasi temukan, metode ekstensi AsTask digunakan untuk mengonversi operasi yang dikembalikan ke tugas yang dapat ditunggu, melaporkan kemajuan, dan dapat dibatalkan.

Setelah operasi impor selesai, status operasi dapat diperoleh dari objek PhotoImportImportItemsResult yang dikembalikan oleh ImportItemsAsync. Contoh ini menghasilkan informasi status ke konsol debug lalu akhirnya, mengatur token pembatalan ke null.

private async void importButton_Click(object sender, RoutedEventArgs e)
{
    cts = new CancellationTokenSource();
    progressBar.Value = 0;

    try
    {
        if (itemsResult.SelectedTotalCount <= 0)
        {
            System.Diagnostics.Debug.WriteLine("Nothing Selected for Import.");
        }
        else
        {
            var progress = new Progress<PhotoImportProgress>((result) =>
            {
                progressBar.Value = result.ImportProgress;
            });

            this.itemsResult.ItemImported += async (s, a) =>
            {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    System.Diagnostics.Debug.WriteLine(String.Format("Imported: {0}", a.ImportedItem.Name));
                });
            };

            // import items from the our list of selected items
            this.importedResult = await this.itemsResult.ImportItemsAsync().AsTask(cts.Token, progress);

            if (importedResult != null)
            {
                StringBuilder importedSummary = new StringBuilder();
                importedSummary.AppendLine(String.Format("Photos Imported   \t:  {0} ", importedResult.PhotosCount));
                importedSummary.AppendLine(String.Format("Videos Imported    \t:  {0} ", importedResult.VideosCount));
                importedSummary.AppendLine(String.Format("SideCars Imported   \t:  {0} ", importedResult.SidecarsCount));
                importedSummary.AppendLine(String.Format("Siblings Imported   \t:  {0} ", importedResult.SiblingsCount));
                importedSummary.AppendLine(String.Format("Total Items Imported \t:  {0} ", importedResult.TotalCount));
                importedSummary.AppendLine(String.Format("Total Bytes Imported \t:  {0} ", importedResult.TotalSizeInBytes));

                System.Diagnostics.Debug.WriteLine(importedSummary.ToString());
            }

            if (!this.importedResult.HasSucceeded)
            {
                System.Diagnostics.Debug.WriteLine("ImportItemsAsync did not succeed or was not completed");
            }
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Files could not be imported. " + "Exception: " + ex.ToString());
    }

    cts = null;
}

Menghapus item yang diimpor

Untuk menghapus item yang berhasil diimpor dari sumber tempat item diimpor, pertama-tama inisialisasi token pembatalan sehingga operasi penghapusan dapat dibatalkan dan atur nilai bilah kemajuan ke 0. Pastikan bahwa PhotoImportImportItemsResult yang dikembalikan dari ImportItemsAsync tidak null. Jika tidak, sekali lagi buat objek Kemajuan untuk memberikan panggilan balik kemajuan untuk operasi penghapusan. Panggil DeleteImportedItemsFromSourceAsync untuk mulai menghapus item yang diimpor. Us AsTask untuk mengonversi hasilnya menjadi tugas yang dapat ditunggu dengan kemampuan kemajuan dan pembatalan. Setelah menunggu, objek PhotoImportDeleteImportedItemsFromSourceResult yang dikembalikan dapat digunakan untuk mendapatkan dan menampilkan informasi status tentang operasi penghapusan.


private async void deleteButton_Click(object sender, RoutedEventArgs e)
{
    cts = new CancellationTokenSource();
    progressBar.Value = 0;

    try
    {
        if (importedResult == null)
        {
            System.Diagnostics.Debug.WriteLine("Nothing was imported for deletion.");
        }
        else
        {
            var progress = new Progress<double>((result) =>
            {
                this.progressBar.Value = result;
            });

            PhotoImportDeleteImportedItemsFromSourceResult deleteResult = await this.importedResult.DeleteImportedItemsFromSourceAsync().AsTask(cts.Token, progress);

            if (deleteResult != null)
            {
                StringBuilder deletedResults = new StringBuilder();
                deletedResults.AppendLine(String.Format("Total Photos Deleted:\t{0} ", deleteResult.PhotosCount));
                deletedResults.AppendLine(String.Format("Total Videos Deleted:\t{0} ", deleteResult.VideosCount));
                deletedResults.AppendLine(String.Format("Total Sidecars Deleted:\t{0} ", deleteResult.SidecarsCount));
                deletedResults.AppendLine(String.Format("Total Sibilings Deleted:\t{0} ", deleteResult.SiblingsCount));
                deletedResults.AppendLine(String.Format("Total Files Deleted:\t{0} ", deleteResult.TotalCount));
                deletedResults.AppendLine(String.Format("Total Bytes Deleted:\t{0} ", deleteResult.TotalSizeInBytes));
                System.Diagnostics.Debug.WriteLine(deletedResults.ToString());
            }

            if (!deleteResult.HasSucceeded)
            {
                System.Diagnostics.Debug.WriteLine("Delete operation did not succeed or was not completed");
            }
        }

    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Files could not be Deleted." + "Exception: " + ex.ToString());
    }

    // set the CancellationTokenSource to null when the work is complete.
    cts = null;


}