Bagikan melalui


Membuat pengikatan data

Jika Anda telah merancang UI dengan gambar tempat penampung dan teks template, tutorial ini menunjukkan cara menghubungkannya ke data nyata dengan menggunakan pengikatan data. Pelajari cara memformat data, menjaga UI dan data Anda tetap sinkron, dan meningkatkan ketahanan kode.

Dalam tutorial ini, Anda mempelajari cara mengganti boilerplate Anda dengan pengikatan data dan membuat tautan langsung lainnya antara UI dan data Anda. Anda juga mempelajari cara memformat atau mengonversi data untuk ditampilkan, dan menjaga UI dan data Anda tetap sinkron. Ketika Anda menyelesaikan tutorial ini, Anda dapat meningkatkan kesederhanaan dan organisasi kode XAML dan C#, sehingga lebih mudah untuk dipertahankan dan diperluas.

Anda mulai dengan versi sampel PhotoLab yang disederhanakan. Versi pemula ini mencakup lapisan data lengkap ditambah tata letak halaman XAML dasar, dan meninggalkan banyak fitur untuk membuat kode lebih mudah dijelajahi. Tutorial ini tidak dibangun ke aplikasi lengkap, jadi pastikan untuk memeriksa versi akhir untuk melihat fitur seperti animasi kustom dan tata letak adaptif. Anda dapat menemukan versi akhir di folder akar windows-appsample-photo-lab repo.

Aplikasi sampel PhotoLab memiliki dua halaman. Halaman utama menampilkan tampilan galeri foto, bersama dengan beberapa informasi tentang setiap file gambar.

Cuplikan layar halaman utama aplikasi PhotoLab memperlihatkan tampilan galeri foto dengan metadata gambar.

Halaman detail menampilkan satu foto setelah Anda memilihnya. Menu pengeditan flyout memungkinkan Anda mengubah, mengganti nama, dan menyimpan foto.

Cuplikan layar halaman detail aplikasi PhotoLab memperlihatkan satu foto dengan opsi pengeditan.

Prasyarat

Bagian 0: Dapatkan kode pemula dari GitHub

Untuk tutorial ini, Anda mulai dengan versi sampel PhotoLab yang disederhanakan.

  1. Buka halaman GitHub untuk sampel: https://github.com/Microsoft/Windows-appsample-photo-lab.

  2. Selanjutnya, Anda perlu mengkloning atau mengunduh sampel. Pilih tombol kloning atau unduh. Sub-menu muncul. menu Kloning atau unduh di halaman GitHub sampel PhotoLab

    Jika Anda tidak terbiasa dengan GitHub:

    sebuah. Pilih Unduh ZIP dan simpan file secara lokal. Tindakan ini mengunduh file .zip yang berisi semua file proyek yang Anda butuhkan.

    b. Ekstrak file. Gunakan File Explorer untuk menelusuri file .zip yang baru saja Anda unduh, klik kanan, dan pilih Ekstrak Semua....

    c. Telusuri ke salinan sampel lokal Anda, dan buka direktori Windows-appsample-photo-lab-master\xaml-basics-starting-points\data-binding.

    Jika Anda terbiasa dengan GitHub:

    sebuah. Mengkloning cabang utama dari repositori secara lokal.

    b. Telusuri ke direktori Windows-appsample-photo-lab\xaml-basics-starting-points\data-binding.

  3. Klik dua kali Photolab.sln untuk membuka solusi di Visual Studio.

Bagian 1: Ganti tempat penampung

Di bagian ini, Anda membuat pengikatan satu kali di XAML templat data untuk menampilkan gambar nyata dan metadata gambar alih-alih konten tempat penampung.

Pengikatan satu kali ditujukan untuk data yang hanya dibaca dan tidak berubah. Mereka performa tinggi dan mudah dibuat, sehingga Anda dapat menampilkan himpunan data besar dalam GridView dan ListView kontrol.

Ganti tempat penampung dengan pengikatan satu kali

  1. Buka folder xaml-basics-starting-points\data-binding dan luncurkan file PhotoLab.sln di Visual Studio.

  2. Pastikan Platform Solusi Anda diatur ke x86 atau x64, bukan Arm, lalu jalankan aplikasi. Langkah ini menunjukkan status aplikasi dengan placeholder UI, sebelum binding ditambahkan.

    Menjalankan aplikasi dengan teks dan gambar tempat penampung

  3. Buka MainPage.xaml dan cari DataTemplate bernama ImageGridView_DefaultItemTemplate. Anda akan memperbarui templat ini untuk menggunakan pengikatan data.

    Sebelumnya:

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate">
    

    Nilai x:Key digunakan oleh ImageGridView untuk memilih templat ini untuk menampilkan objek data.

  4. Tambahkan nilai x:DataType ke templat.

    Setelah:

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate"
                  x:DataType="local:ImageFileInfo">
    

    x:DataType menunjukkan tipe untuk templat ini. Dalam hal ini, ini adalah templat untuk kelas ImageFileInfo (di mana local: menunjukkan namespace lokal, seperti yang didefinisikan dalam deklarasi xmlns di dekat bagian atas file).

    Anda perlu x:DataType saat menggunakan ekspresi x:Bind dalam templat data, seperti yang dijelaskan berikut.

  5. Di DataTemplate, temukan elemen Image bernama ItemImage dan ganti nilai Source seperti yang ditunjukkan.

    Sebelumnya:

    <Image x:Name="ItemImage"
           Source="/Assets/StoreLogo.png"
           Stretch="Uniform" />
    

    Setelah:

    <Image x:Name="ItemImage"
           Source="{x:Bind ImageSource}"
           Stretch="Uniform" />
    

    x:Name mengidentifikasi elemen XAML sehingga Anda dapat merujuknya ke tempat lain di XAML dan di kode-belakang.

    ekspresi memberikan nilai ke properti UI dengan mendapatkan nilai dari properti objek data . Dalam templat, properti yang ditunjukkan adalah properti dari apa pun yang x:DataType diatur ke. Jadi dalam hal ini, sumber data adalah properti ImageFileInfo.ImageSource.

    Nota

    Nilai x:Bind juga memungkinkan editor mengetahui tentang jenis data, sehingga Anda dapat menggunakan IntelliSense alih-alih mengetikkan nama properti dalam ekspresi x:Bind. Cobalah pada kode yang baru saja Anda tempel: tempatkan kursor tepat setelah x:Bind dan tekan Spacebar untuk melihat daftar properti yang dapat Anda ikat.

  6. Ganti nilai kontrol UI lainnya dengan cara yang sama. (Coba lakukan ini dengan IntelliSense alih-alih menyalin/menempelkan!)

    Sebelumnya:

    <TextBlock Text="Placeholder" ... />
    <StackPanel ... >
        <TextBlock Text="PNG file" ... />
        <TextBlock Text="50 x 50" ... />
    </StackPanel>
    <muxc:RatingControl Value="3" ... />
    

    Setelah:

    <TextBlock Text="{x:Bind ImageTitle}" ... />
    <StackPanel ... >
        <TextBlock Text="{x:Bind ImageFileType}" ... />
        <TextBlock Text="{x:Bind ImageDimensions}" ... />
    </StackPanel>
    <muxc:RatingControl Value="{x:Bind ImageRating}" ... />
    

Jalankan aplikasi untuk melihat tampilannya sejauh ini. Tidak ada tempat penampung lagi! Anda memulai dengan baik.

Menjalankan aplikasi dengan gambar dan teks nyata, bukan tempat penampung

Nota

Jika Anda ingin bereksperimen lebih lanjut, coba tambahkan TextBlock baru ke templat data, dan gunakan trik x:Bind IntelliSense untuk menemukan properti yang akan ditampilkan.

Di bagian ini, Anda membuat pengikatan satu kali di halaman XAML untuk menyambungkan tampilan galeri ke koleksi gambar. Pengikatan ini menggantikan kode prosedural yang ada di code-behind. Anda juga membuat tombol Hapus untuk melihat bagaimana tampilan galeri berubah saat Anda menghapus gambar dari koleksi. Pada saat yang sama, Anda mempelajari cara mengikat peristiwa ke penanganan aktivitas untuk lebih banyak fleksibilitas daripada penanganan aktivitas tradisional.

Semua pengikatan yang tercakup sejauh ini berada di dalam templat data dan merujuk ke properti kelas yang ditunjukkan oleh nilai x:DataType. Bagaimana dengan XAML lainnya di halaman Anda?

x:Bind ekspresi di luar templat data selalu mengikat ke halaman itu sendiri. Ini berarti Anda dapat mereferensikan apa pun yang Anda masukkan ke dalam code-behind atau mendeklarasikan di XAML, termasuk properti kustom dan properti kontrol UI lain di halaman (selama mereka memiliki nilai x:Name).

Dalam sampel PhotoLab, Anda menggunakan pengikatan seperti ini untuk menyambungkan kontrol utama GridView langsung ke kumpulan gambar, alih-alih melakukannya di code-behind. Nantinya, Anda akan melihat contoh lain.

Mengikat kontrol GridView utama ke koleksi Gambar

  1. Di MainPage.xaml.cs, temukan metode GetItemsAsync dan hapus kode yang mengatur ItemsSource.

    Sebelumnya:

    ImageGridView.ItemsSource = Images;
    

    Setelah:

    // Replaced with XAML binding:
    // ImageGridView.ItemsSource = Images;
    
  2. Di MainPage.xaml, temukan GridView bernama ImageGridView dan tambahkan atribut ItemsSource. Untuk nilai , gunakan ekspresi x:Bind yang mengacu pada properti Images yang diterapkan di code-behind.

    Sebelumnya:

    <GridView x:Name="ImageGridView"
    

    Setelah:

    <GridView x:Name="ImageGridView"
              ItemsSource="{x:Bind Images}"
    

    Properti Images berjenis ObservableCollection<ImageFileInfo>, sehingga item individual yang ditampilkan dalam GridView berjenis ImageFileInfo. Jenis ini cocok dengan nilainya x:DataType yang dijelaskan di Bagian 1.

Semua pengikatan yang Anda lihat sebelumnya adalah pengikatan baca-saja satu kali, yang merupakan perilaku default untuk ekspresi biasa x:Bind . Data hanya dimuat saat inisialisasi, yang menghasilkan pengikatan dengan performa tinggi - sempurna untuk mendukung berbagai tampilan kompleks dari himpunan data besar.

Bahkan pengikatan ItemsSource yang baru saja Anda tambahkan adalah pengikatan baca-saja satu kali dengan nilai properti yang tidak berubah, tetapi ada perbedaan penting untuk dibuat di sini. Nilai properti Images yang tidak berubah adalah satu instans tertentu dari koleksi, diinisialisasi sekali seperti yang ditunjukkan di sini.

private ObservableCollection<ImageFileInfo> Images { get; }
    = new ObservableCollection<ImageFileInfo>();

Nilai properti Images tidak pernah berubah, tetapi karena properti berjenis ObservableCollection<T>, konten koleksi dapat berubah, dan binding secara otomatis mendeteksi perubahan dan memperbarui UI.

Untuk menguji perilaku ini, tambahkan sementara tombol yang menghapus gambar yang saat ini dipilih. Tombol ini tidak berada dalam versi akhir karena memilih gambar akan membawa Anda ke halaman detail. Namun, perilaku ObservableCollection<T> masih penting dalam sampel PhotoLab akhir karena XAML diinisialisasi di konstruktor halaman melalui pemanggilan metode InitializeComponent, tetapi koleksi Images diisi nanti dalam metode GetItemsAsync.

Menambahkan tombol hapus

  1. Di MainPage.xaml, temukan CommandBar bernama MainCommandBar dan tambahkan tombol baru sebelum tombol zoom. (Kontrol zoom belum berfungsi. Anda akan menghubungkan mereka di bagian berikutnya dari tutorial.)

    <AppBarButton Icon="Delete"
                  Label="Delete selected image"
                  Click="{x:Bind DeleteSelectedImage}" />
    

    Jika Anda sudah terbiasa dengan XAML, nilai Click ini mungkin terlihat tidak biasa. Di versi XAML sebelumnya, Anda harus mengatur ini ke metode dengan tanda tangan penanganan aktivitas tertentu, biasanya menyertakan parameter untuk pengirim peristiwa dan objek argumen khusus peristiwa. Anda masih dapat menggunakan teknik ini ketika Anda memerlukan argumen peristiwa, tetapi dengan x:Bind, Anda juga dapat terhubung ke metode lain. Misalnya, jika Anda tidak memerlukan data peristiwa, Anda dapat terhubung ke metode yang tidak memiliki parameter, seperti yang kami lakukan di sini.

  2. Di MainPage.xaml.cs, tambahkan metode DeleteSelectedImage.

    private void DeleteSelectedImage() =>
        Images.Remove(ImageGridView.SelectedItem as ImageFileInfo);
    

    Metode ini hanya menghapus gambar yang dipilih dari koleksi Images.

Sekarang jalankan aplikasi dan gunakan tombol untuk menghapus beberapa gambar. Seperti yang Anda lihat, UI diperbarui secara otomatis, berkat pengikatan data dan tipe ObservableCollection<T>.

Nota

Kode ini hanya menghapus instans ImageFileInfo dari koleksi Images di aplikasi yang sedang berjalan. Ini tidak menghapus file gambar dari komputer.

Bagian 3: Menyiapkan penggeser zoom

Di bagian ini, Anda akan membuat pengikatan satu arah dari kontrol di templat data ke penggeser zoom, yang berada di luar templat. Anda juga akan mempelajari bahwa Anda dapat menggunakan pengikatan data dengan banyak properti kontrol, bukan hanya yang paling jelas seperti TextBlock.Text dan Image.Source.

Mengikat templat data gambar ke penggeser zoom

  • Temukan DataTemplate bernama ImageGridView_DefaultItemTemplate dan ganti nilai **Height** dan Width dari kontrol Grid di bagian atas template.

    Sebelum

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate"
                  x:DataType="local:ImageFileInfo">
        <Grid Height="200"
              Width="200"
              Margin="{StaticResource LargeItemMargin}">
    

    Sesudah

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate"
                  x:DataType="local:ImageFileInfo">
        <Grid Height="{Binding Value, ElementName=ZoomSlider}"
              Width="{Binding Value, ElementName=ZoomSlider}"
              Margin="{StaticResource LargeItemMargin}">
    

Apakah Anda melihat bahwa ini adalah ekspresi Binding, dan bukan ekspresi x:Bind? Ini adalah cara lama untuk melakukan pengikatan data, dan sebagian besar sudah usang. x:Bind melakukan hampir semua yang Binding lakukan, dan banyak lagi. Namun, saat Anda menggunakan x:Bind dalam templat data, templat tersebut mengikat ke jenis yang dideklarasikan dalam nilai x:DataType. Jadi bagaimana Anda mengikat sesuatu dalam templat ke sesuatu di halaman XAML atau di code-behind? Anda harus menggunakan ekspresi Binding gaya lama.

ekspresi Binding tidak mengenali nilai x:DataType, tetapi ekspresi Binding ini memiliki nilai ElementName yang berfungsi hampir sama. Ini memberi tahu mesin pengikatan bahwa Nilai Pengikatan adalah pengikatan ke properti Value dari elemen yang ditentukan pada halaman (yaitu, elemen dengan nilai x:Name tersebut). Jika Anda ingin mengikat properti di code-behind, itu akan terlihat seperti {Binding MyCodeBehindProperty, ElementName=page} di mana page mengacu pada nilai x:Name yang diatur dalam elemen Page di XAML.

Nota

Secara default, ekspresi Binding adalah carasatu, yang berarti bahwa ekspresi tersebut akan secara otomatis memperbarui UI saat nilai properti terikat berubah.

Sebaliknya, default untuk x:Bind adalah satuwaktu, yang berarti bahwa setiap perubahan pada properti terikat diabaikan. Ini adalah default karena ini adalah opsi performa paling tinggi, dan sebagian besar pengikatannya adalah data statis baca-saja.

Pelajaran di sini adalah bahwa jika Anda menggunakan x:Bind dengan properti yang dapat mengubah nilainya, pastikan untuk menambahkan Mode=OneWay atau Mode=TwoWay. Anda akan melihat contoh ini di bagian berikutnya.

Jalankan aplikasi dan gunakan slider untuk mengubah dimensi templat gambar. Seperti yang Anda lihat, efeknya cukup kuat tanpa membutuhkan banyak kode.

Menjalankan aplikasi dengan penggeser zoom yang menunjukkan

Nota

Untuk tantangan, coba ikat properti UI lainnya ke properti penggeser zoom Value, atau ke penggeser lain yang Anda tambahkan setelah penggeser zoom. Misalnya, Anda dapat mengikat properti FontSizeTitleTextBlock ke slider baru dengan nilai default 24. Pastikan untuk menetapkan nilai minimum dan maksimum yang wajar.

Bagian 4: Meningkatkan pengalaman zoom

Di bagian ini, Anda akan menambahkan properti ItemSize kustom ke code-behind dan membuat pengikatan satu arah dari templat gambar ke properti baru. Nilai ItemSize akan diperbarui oleh penggeser zoom dan faktor lain, seperti pengalih Paskan ke layar dan ukuran jendela, menjadikan pengalaman yang lebih menyempurnakan.

Tidak seperti properti kontrol bawaan, properti kustom Anda tidak secara otomatis memperbarui UI, bahkan dengan pengikatan satu arah dan dua arah. Mereka bekerja dengan baik dengan pengikatan waktu satu, tetapi jika Anda ingin perubahan properti Anda benar-benar muncul di UI Anda, Anda perlu melakukan beberapa pekerjaan.

Buat properti ItemSize sehingga memperbarui UI

  1. Di MainPage.xaml.cs, ubah tanda tangan kelas MainPage sehingga mengimplementasikan antarmuka INotifyPropertyChanged.

    Sebelumnya:

    public sealed partial class MainPage : Page
    

    Setelah:

    public sealed partial class MainPage : Page, INotifyPropertyChanged
    

    Ini menginformasikan sistem pengikatan bahwa sistem MainPage memiliki acara PropertyChanged (ditambahkan berikutnya) yang dapat dipantau oleh pengikatan untuk memperbarui UI.

  2. Tambahkan acara PropertyChanged ke kelas MainPage.

    public event PropertyChangedEventHandler PropertyChanged;
    

    Acara ini menyediakan implementasi lengkap yang diperlukan oleh antarmuka INotifyPropertyChanged. Namun, agar memiliki efek apa pun, Anda harus secara eksplisit memicu peristiwa pada properti kustom Anda.

  3. Tambahkan properti ItemSize dan naikkan peristiwa PropertyChanged di setternya.

    public double ItemSize
    {
        get => _itemSize;
        set
        {
            if (_itemSize != value)
            {
                _itemSize = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize)));
            }
        }
    }
    private double _itemSize;
    

    Properti ItemSize mengekspos nilai bidang _itemSize privat. Menggunakan bidang dukungan seperti ini memungkinkan properti untuk memeriksa apakah nilai baru sama dengan nilai lama sebelum menaikkan peristiwa PropertyChanged yang berpotensi tidak perlu.

    Peristiwa itu sendiri dimunculkan oleh metode Invoke. Tanda tanya memeriksa apakah peristiwa PropertyChanged null - yaitu, apakah ada penanganan aktivitas yang telah ditambahkan. Setiap pengikatan satu arah atau dua arah menambahkan penanganan aktivitas di belakang layar, tetapi jika tidak ada yang mendengarkan, tidak ada lagi yang akan terjadi di sini. Namun, jika tidak null, maka dipanggil dengan referensi ke sumber peristiwa (halaman itu sendiri, diwakili oleh kata kunci ) dan objek event-args yang menunjukkan nama properti. Dengan informasi ini, setiap pengikatan satu arah atau dua arah ke properti ItemSize akan mendapatkan pemberitahuan tentang perubahan apa pun, sehingga dapat memperbarui antarmuka pengguna yang terikat.

  4. Di MainPage.xaml, temukan DataTemplate yang bernama ImageGridView_DefaultItemTemplate dan ganti nilai Height serta Width dari kontrol Grid di bagian atas templat. (Jika Anda melakukan pengikatan kontrol-ke-kontrol di bagian sebelumnya dari tutorial ini, satu-satunya perubahan adalah mengganti Value dengan ItemSize dan ZoomSlider dengan page. Pastikan untuk melakukan ini untuk Height dan Width!)

    Sebelum

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate"
                  x:DataType="local:ImageFileInfo">
        <Grid Height="{Binding Value, ElementName=ZoomSlider}"
            Width="{Binding Value, ElementName=ZoomSlider}"
            Margin="{StaticResource LargeItemMargin}">
    

    Sesudah

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate"
                  x:DataType="local:ImageFileInfo">
        <Grid Height="{Binding ItemSize, ElementName=page}"
              Width="{Binding ItemSize, ElementName=page}"
              Margin="{StaticResource LargeItemMargin}">
    

Sekarang setelah UI dapat merespons perubahan ItemSize, Anda harus benar-benar melakukan beberapa penyesuaian. Seperti disebutkan sebelumnya, nilai ItemSize dihitung dari status saat ini dari berbagai kontrol UI, tetapi perhitungan harus dilakukan setiap kali kontrol tersebut mengubah status. Untuk melakukan ini, Anda akan menggunakan pengikatan peristiwa sehingga perubahan UI tertentu akan memanggil metode pembantu yang memperbarui ItemSize.

Perbarui nilai properti ItemSize

  1. Tambahkan metode DetermineItemSize ke MainPage.xaml.cs.

    private void DetermineItemSize()
    {
        if (FitScreenToggle != null
            && FitScreenToggle.IsOn == true
            && ImageGridView != null
            && ZoomSlider != null)
        {
            // The 'margins' value represents the total of the margins around the
            // image in the grid item. 8 from the ItemTemplate root grid + 8 from
            // the ItemContainerStyle * (Right + Left). If those values change,
            // this value needs to be updated to match.
            int margins = (int)this.Resources["LargeItemMarginValue"] * 4;
            double gridWidth = ImageGridView.ActualWidth -
                (int)this.Resources["DefaultWindowSidePaddingValue"];
            double ItemWidth = ZoomSlider.Value + margins;
            // We need at least 1 column.
            int columns = (int)Math.Max(gridWidth / ItemWidth, 1);
    
            // Adjust the available grid width to account for margins around each item.
            double adjustedGridWidth = gridWidth - (columns * margins);
    
            ItemSize = (adjustedGridWidth / columns);
        }
        else
        {
            ItemSize = ZoomSlider.Value;
        }
    }
    
  2. Di MainPage.xaml, navigasikan ke bagian atas file dan tambahkan pengikatan peristiwa SizeChanged ke elemen Page.

    Sebelumnya:

    <Page x:Name="page"
    

    Setelah:

    <Page x:Name="page"
          SizeChanged="{x:Bind DetermineItemSize}"
    
  3. Temukan Slider bernama ZoomSlider (di bagian Page.Resources) dan tambahkan pengikatan peristiwa ValueChanged.

    Sebelumnya:

    <Slider x:Name="ZoomSlider"
    

    Setelah:

    <Slider x:Name="ZoomSlider"
            ValueChanged="{x:Bind DetermineItemSize}"
    
  4. Temukan ToggleSwitch bernama FitScreenToggle dan tambahkan pengikatan peristiwa Toggled.

    Sebelumnya:

    <ToggleSwitch x:Name="FitScreenToggle"
    

    Setelah:

    <ToggleSwitch x:Name="FitScreenToggle"
                  Toggled="{x:Bind DetermineItemSize}"
    

Jalankan aplikasi dan gunakan penggeser zoom serta tombol Paskan ke layar untuk mengubah dimensi templat gambar. Seperti yang Anda lihat, perubahan terbaru memungkinkan pengalaman zoom/ubah ukuran yang lebih halus sambil menjaga kode tetap terorganisir dengan baik.

Menjalankan aplikasi dengan penyesuaian ke layar diaktifkan

Nota

Untuk tantangan, coba tambahkan TextBlock setelah ZoomSlider dan ikat properti Text ke properti ItemSize. Karena tidak ada dalam templat data, Anda dapat menggunakan x:Bind alih-alih Binding seperti pada pengikatan ItemSize sebelumnya.

Bagian 5: Mengaktifkan pengeditan pengguna

Di sini, Anda akan membuat pengikatan dua arah untuk memungkinkan pengguna memperbarui nilai, termasuk judul gambar, peringkat, dan berbagai efek visual.

Untuk mencapai hal ini, Anda akan memperbarui DetailPageyang ada , yang menyediakan penampil gambar tunggal, kontrol zoom, dan antarmuka pengguna pengeditan.

Namun, pertama-tama, Anda perlu melampirkan DetailPage sehingga aplikasi menavigasi ke sana saat pengguna mengklik gambar dalam tampilan galeri.

Lampirkan Halaman Detail

  1. Di MainPage.xaml, temukan GridView dengan nama ImageGridView. Untuk membuat item dapat diklik, atur IsItemClickEnabled ke True dan tambahkan penanganan aktivitas ItemClick.

    Petunjuk / Saran

    Jika Anda mengetik perubahan di bawah ini alih-alih menyalin/menempelkan, Anda akan melihat pop-up IntelliSense yang bertuliskan "<Penanganan Aktivitas Baru>". Jika Anda menekan tombol Tab, ini akan mengisi nilai dengan nama handler metode default, dan secara otomatis membuat rangkuman untuk metode yang ditunjukkan pada langkah berikutnya. Anda kemudian dapat menekan F12 untuk menelusuri metode di code-behind.

    Sebelumnya:

    <GridView x:Name="ImageGridView">
    

    Setelah:

    <GridView x:Name="ImageGridView"
              IsItemClickEnabled="True"
              ItemClick="ImageGridView_ItemClick">
    

    Nota

    Kami menggunakan penanganan aktivitas konvensional di sini alih-alih ekspresi x:Bind. Ini karena kita perlu melihat data peristiwa, seperti yang ditunjukkan berikutnya.

  2. Di MainPage.xaml.cs, tambahkan penanganan aktivitas (atau isi, jika Anda menggunakan tip di langkah terakhir).

    private void ImageGridView_ItemClick(object sender, ItemClickEventArgs e)
    {
        this.Frame.Navigate(typeof(DetailPage), e.ClickedItem);
    }
    

    Metode ini menavigasi ke halaman detail dengan meneruskan item yang diklik, yaitu objek ImageFileInfo yang digunakan oleh DetailPage.OnNavigatedTo untuk menginisialisasi halaman. Anda tidak perlu menerapkan metode itu dalam tutorial ini, tetapi Anda dapat melihat untuk melihat apa yang dilakukannya.

  3. (Opsional) Hapus atau komentari kontrol apa pun yang Anda tambahkan di play-point sebelumnya yang berfungsi dengan gambar yang saat ini dipilih. Menjaga mereka tidak akan menyakiti apa pun, tetapi sekarang jauh lebih sulit untuk memilih gambar tanpa menavigasi ke halaman detail.

Sekarang setelah Anda menghubungkan dua halaman, jalankan aplikasi dan lihat-lihat. Semuanya berfungsi kecuali kontrol pada panel pengeditan, yang tidak merespons saat Anda mencoba mengubah nilai.

Seperti yang Anda lihat, kotak teks judul memang menampilkan judul dan memungkinkan Anda mengetik perubahan. Anda harus mengubah fokus ke kontrol lain untuk menerapkan perubahan, tetapi judul di sudut kiri atas layar belum diperbarui.

Semua kontrol sudah terikat menggunakan ekspresi x:Bind biasa yang kami bahas di Bagian 1. Jika Anda ingat, ini berarti semuanya adalah pengikatan satu kali, yang menjelaskan mengapa perubahan pada nilai tidak terdaftar. Untuk memperbaiki ini, yang harus kita lakukan adalah mengubahnya menjadi pengikatan dua arah.

Membuat kontrol pengeditan interaktif

  1. Di DetailPage.xaml, temukan bernama TitleTextBlock dan kontrol RatingControl setelahnya, dan perbarui ekspresi mereka untuk menyertakan Mode=TwoWay.

    Sebelumnya:

    <TextBlock x:Name="TitleTextBlock"
               Text="{x:Bind item.ImageTitle}"
               ... >
    <muxc:RatingControl Value="{x:Bind item.ImageRating}"
                            ... >
    

    Setelah:

    <TextBlock x:Name="TitleTextBlock"
               Text="{x:Bind item.ImageTitle, Mode=TwoWay}"
               ... >
    <muxc:RatingControl Value="{x:Bind item.ImageRating, Mode=TwoWay}"
                            ... >
    
  2. Lakukan hal yang sama untuk semua slider efek yang datang setelah kontrol peringkat.

    <Slider Header="Exposure"    ... Value="{x:Bind item.Exposure, Mode=TwoWay}" ...
    <Slider Header="Temperature" ... Value="{x:Bind item.Temperature, Mode=TwoWay}" ...
    <Slider Header="Tint"        ... Value="{x:Bind item.Tint, Mode=TwoWay}" ...
    <Slider Header="Contrast"    ... Value="{x:Bind item.Contrast, Mode=TwoWay}" ...
    <Slider Header="Saturation"  ... Value="{x:Bind item.Saturation, Mode=TwoWay}" ...
    <Slider Header="Blur"        ... Value="{x:Bind item.Blur, Mode=TwoWay}" ...
    

Mode dua arah, seperti yang mungkin Anda harapkan, berarti bahwa data bergerak ke kedua arah setiap kali ada perubahan di kedua sisi.

Seperti pengikatan satu arah yang dibahas sebelumnya, pengikatan dua arah ini sekarang akan memperbarui UI setiap kali properti terikat berubah, berkat implementasi INotifyPropertyChanged di kelas ImageFileInfo. Namun, dengan pengikatan dua arah, nilai juga akan berpindah dari UI ke properti terikat setiap kali pengguna berinteraksi dengan kontrol. Tidak ada lagi yang diperlukan di sisi XAML.

Jalankan aplikasi dan coba kontrol pengeditan. Seperti yang Anda lihat, saat Anda membuat perubahan, sekarang berdampak pada nilai gambar, dan perubahan tersebut bertahan saat Anda menavigasi kembali ke halaman utama.

Bagian 6: Memformat nilai melalui pengikatan fungsi

Satu masalah terakhir tetap ada. Saat Anda memindahkan penggeser efek, label di sampingnya masih tidak berubah.

Slider Efek dengan nilai label default

Bagian terakhir dalam tutorial ini adalah menambahkan pengikatan yang memformat nilai slider untuk ditampilkan.

Mengikat label effect-slider dan memformat nilai untuk tampilan

  1. Temukan TextBlock setelah slider Exposure dan ganti nilai Text dengan ekspresi pengikatan yang diperlihatkan di sini.

    Sebelumnya:

    <Slider Header="Exposure" ... />
    <TextBlock ... Text="0.00" />
    

    Setelah:

    <Slider Header="Exposure" ... />
    <TextBlock ... Text="{x:Bind item.Exposure.ToString('N', culture), Mode=OneWay}" />
    

    Ini disebut pengikatan fungsi karena Anda mengikat ke nilai pengembalian metode. Metode harus dapat diakses melalui kode di balik halaman atau jenis x:DataType jika Anda berada dalam templat data. Dalam kasus ini, metode tersebut adalah metode .NET ToString yang umum dikenal, yang diakses melalui properti 'item' dari halaman, dan kemudian melalui properti Exposure dari 'item'. (Ini menggambarkan bagaimana Anda dapat mengikat metode dan properti yang sangat bersarang dalam rantai koneksi.)

    Pengikatan fungsi adalah cara ideal untuk memformat nilai agar dapat ditampilkan, karena Anda dapat meneruskan sumber pengikatan lain sebagai argumen metode, dan ekspresi pengikatan akan mendeteksi perubahan pada nilai tersebut sesuai dengan mode satu arah. Dalam contoh ini, argumen budaya adalah referensi ke bidang yang tidak berubah yang diimplementasikan dalam code-behind, tetapi bisa saja dengan mudah menjadi properti yang memunculkan peristiwa PropertyChanged. Dalam hal ini, setiap perubahan pada nilai properti akan menyebabkan ekspresi x:Bind memanggil ToString dengan nilai baru lalu memperbarui UI dengan hasilnya.

  2. Lakukan hal yang sama untuk TextBlockyang memberikan label pada slider efek lainnya.

    <Slider Header="Temperature" ... />
    <TextBlock ... Text="{x:Bind item.Temperature.ToString('N', culture), Mode=OneWay}" />
    
    <Slider Header="Tint" ... />
    <TextBlock ... Text="{x:Bind item.Tint.ToString('N', culture), Mode=OneWay}" />
    
    <Slider Header="Contrast" ... />
    <TextBlock ... Text="{x:Bind item.Contrast.ToString('N', culture), Mode=OneWay}" />
    
    <Slider Header="Saturation" ... />
    <TextBlock ... Text="{x:Bind item.Saturation.ToString('N', culture), Mode=OneWay}" />
    
    <Slider Header="Blur" ... />
    <TextBlock ... Text="{x:Bind item.Blur.ToString('N', culture), Mode=OneWay}" />
    

Sekarang saat Anda menjalankan aplikasi, semuanya berfungsi, termasuk label penggeser.

Slider Efek dengan label yang berfungsi

Perbedaan antara Pengikatan Data dan x:Bind

Saat membuat pengikatan data di XAML di aplikasi UWP, Anda dapat memilih antara Binding dan x:Bind. Berikut adalah perbedaan utamanya:

  • x:Bind: Menyediakan validasi waktu kompilasi, performa yang lebih baik, dan ditik dengan kuat. Ini paling cocok untuk skenario di mana struktur data dikenal pada waktu kompilasi.
  • Binding: Menawarkan evaluasi runtime dan fleksibilitas yang lebih besar untuk skenario dinamis, seperti ketika struktur data ditentukan pada runtime.

Skenario tidak didukung oleh x:Bind

Meskipun x:Bind sangat efisien, ia memiliki batasan dalam skenario tertentu:

  • Struktur data dinamis: x:Bind tidak dapat digunakan saat struktur data ditentukan pada runtime.
  • Pengikatan elemen ke elemen: Pengikatan langsung antara dua elemen UI tidak didukung oleh x:Bind.
  • Pewarisan DataContext: Tidak seperti Binding, x:Bind tidak secara otomatis mewarisi DataContext elemen induk.
  • Pengikatan dua arah: x:Bind mendukung pengikatan dua arah, memungkinkan perubahan mengalir dari UI kembali ke properti sumber. Agar UI diperbarui saat properti sumber berubah (baik dalam pengikatan satu arah atau dua arah), Anda harus menerapkan INotifyPropertyChanged pada objek data Anda.

Untuk detail dan contoh selengkapnya, lihat sumber daya berikut:

Kesimpulan

Tutorial ini telah memberi Anda pemahaman tentang pengikatan data dan menunjukkan beberapa fungsionalitas yang tersedia. Satu peringatan sebelum kita akhiri: tidak semua hal dapat diikat, dan kadang-kadang nilai yang Anda coba sambungkan tidak kompatibel dengan properti yang Anda coba ikat. Ada banyak fleksibilitas dalam pengikatan, tetapi tidak akan berfungsi dalam setiap situasi.

Salah satu contoh masalah yang tidak diatasi dengan pengikatan adalah ketika kontrol tidak memiliki properti yang cocok untuk diikat, seperti halnya fitur zoom halaman detail. Penggeser zoom ini perlu berinteraksi dengan ScrollViewer yang menampilkan gambar, tetapi ScrollViewer hanya dapat diperbarui melalui metode ChangeView. Dalam hal ini, kami menggunakan penanganan aktivitas konvensional untuk menjaga ScrollViewer dan penggeser zoom tetap sinkron; lihat metode ZoomSlider_ValueChanged dan MainImageScroll_ViewChanged di DetailPage untuk detailnya.

Meskipun demikian, pengikatan adalah cara yang kuat dan fleksibel untuk menyederhanakan kode Anda dan menjaga logika UI Anda terpisah dari logika data Anda. Ini akan membuatnya jauh lebih mudah bagi Anda untuk menyesuaikan salah satu sisi pembagian ini sambil mengurangi risiko memperkenalkan bug di sisi lain.

Salah satu contoh UI dan pemisahan data adalah dengan properti ImageFileInfo.ImageTitle. Properti ini (dan properti ImageRating) sedikit berbeda dari properti ItemSize yang Anda buat di Bagian 4 karena nilai disimpan dalam metadata file (diekspos melalui jenis ImageProperties) alih-alih dalam bidang. Selain itu, ImageTitle mengembalikan nilai ImageName (diatur ke nama file) jika tidak ada judul dalam metadata file.

public string ImageTitle
{
    get => String.IsNullOrEmpty(ImageProperties.Title) ? ImageName : ImageProperties.Title;
    set
    {
        if (ImageProperties.Title != value)
        {
            ImageProperties.Title = value;
            var ignoreResult = ImageProperties.SavePropertiesAsync();
            OnPropertyChanged();
        }
    }
}

Seperti yang Anda lihat, setter memperbarui properti ImageProperties.Title lalu memanggil SavePropertiesAsync untuk menulis nilai baru ke file. (Ini adalah metode asinkron, tetapi kami tidak dapat menggunakan kata kunci await dalam suatu properti - dan Anda tidak ingin melakukannya karena getter dan setter properti harus selesai dengan segera. Jadi sebagai gantinya, Anda akan memanggil metode tersebut dan mengabaikan objek Task yang dikembalikannya.)

Melaju lebih jauh

Sekarang setelah Anda menyelesaikan lab ini, Anda memiliki pengetahuan yang cukup untuk mengatasi masalah sendiri.

Seperti yang mungkin telah Anda perhatikan, jika Anda mengubah tingkat pembesaran tampilan pada halaman detail, tingkat perbesar tampilan akan diatur ulang secara otomatis saat Anda menavigasi mundur, lalu pilih gambar yang sama lagi. Dapatkah Anda mencari tahu cara mempertahankan dan memulihkan tingkat zoom untuk setiap gambar satu per satu? Semoga sukses!

Anda harus memiliki semua informasi yang Anda butuhkan dalam tutorial ini, tetapi jika Anda membutuhkan lebih banyak panduan, dokumentasi pengikatan data bisa diakses hanya dengan satu klik. Mulai di sini: