Tutorial: Membuat pengikatan data

Misalkan Anda telah merancang dan mengimplementasikan UI yang terlihat bagus yang diisi dengan gambar tempat penampung, teks boilerplate "lorem ipsum", dan kontrol yang belum melakukan apa pun. Selanjutnya, Anda harus menghubungkannya ke data nyata dan mengubahnya dari prototipe desain menjadi aplikasi hidup.

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

Anda akan 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 repositori Windows-appsample-photo-lab .

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

Screenshot of the Photo lab main page.

Halaman detail menampilkan satu foto setelah dipilih. Menu pengeditan flyout memungkinkan foto diubah, diganti namanya, dan disimpan.

Screenshot of the Photo lab detail page.

Prasyarat

Bagian 0: Dapatkan kode pemula dari GitHub

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

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

  2. Selanjutnya, Anda harus mengkloning atau mengunduh sampel. Pilih tombol Kloning atau unduh . Sub-menu muncul. The Clone or download menu on the PhotoLab sample's GitHub page

    Jika Anda tidak terbiasa dengan GitHub:

    a. Pilih Unduh ZIP dan simpan file secara lokal. 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 Windows-appsample-photo-lab-master\xaml-basics-starting-points\data-binding direktori.

    Jika Anda terbiasa dengan GitHub:

    a. Kloning cabang utama repositori secara lokal.

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

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

Bagian 1: Ganti tempat penampung

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

Pengikatan satu kali adalah untuk data baca-saja yang tidak berubah, yang berarti mereka berkinerja tinggi dan mudah dibuat, memungkinkan Anda menampilkan kumpulan data besar dalam GridView dan ListView kontrol.

Ganti tempat penampung dengan pengikatan satu kali

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

  2. Pastikan Platform Solusi Anda diatur ke x86 atau x64, bukan Arm, lalu jalankan aplikasi. Ini menunjukkan status aplikasi dengan tempat penampung UI, sebelum pengikatan telah ditambahkan.

    Running app with placeholder images and text

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

    Sebelum:

    <DataTemplate x:Key="ImageGridView_DefaultItemTemplate">
    

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

  4. x:DataType Tambahkan nilai ke templat.

    Setelah:

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

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

    x:DataType diperlukan saat menggunakan x:Bind ekspresi dalam templat data, seperti yang dijelaskan berikutnya.

  5. Dalam , temukan elemen bernama ItemImage dan ganti nilainya Source seperti yang Image ditunjukkanDataTemplate.

    Sebelum:

    <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 di belakang.

    x:Bind 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 telah diatur. Jadi dalam hal ini, sumber data adalah ImageFileInfo.ImageSource properti .

    Catatan

    Nilai ini x:Bind juga memberi tahu editor tentang jenis data, sehingga Anda dapat menggunakan IntelliSense alih-alih mengetikkan nama properti dalam x:Bind ekspresi. Coba pada kode yang baru saja Anda tempel: tempatkan kursor tepat setelahnya 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!)

    Sebelum:

    <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! Kita berangkat ke awal yang baik.

Running app with real images and text instead of placeholders

Catatan

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 sini, Anda akan membuat pengikatan satu kali di halaman XAML untuk menyambungkan tampilan galeri ke koleksi gambar, menggantikan kode prosedural yang ada yang melakukan ini di code-behind. Anda juga akan membuat tombol Hapus untuk melihat bagaimana tampilan galeri berubah saat gambar dihapus dari koleksi. Pada saat yang sama, Anda akan mempelajari cara mengikat peristiwa ke penanganan aktivitas untuk lebih banyak fleksibilitas daripada yang disediakan oleh penanganan aktivitas tradisional.

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

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

Dalam sampel PhotoLab, salah satu penggunaan untuk pengikatan seperti ini adalah untuk menghubungkan kontrol utama GridView langsung ke pengumpulan 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 GetItemsAsync metode dan hapus kode yang mengatur ItemsSource.

    Sebelum:

    ImageGridView.ItemsSource = Images;
    

    Setelah:

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

    Sebelum:

    <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 tipe ImageFileInfo. Ini cocok dengan nilai yang x:DataType dijelaskan di Bagian 1.

Semua pengikatan yang telah kita lihat sejauh ini adalah pengikatan baca-saja satu kali, yang merupakan perilaku default untuk ekspresi biasa x:Bind . Data hanya dimuat pada inisialisasi, yang membuat pengikatan berperforma tinggi - sempurna untuk mendukung beberapa tampilan kompleks 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 yang tidak berubah Images adalah satu instans tertentu dari koleksi, diinisialisasi sekali seperti yang ditunjukkan di sini.

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

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

Untuk menguji ini, kita akan menambahkan tombol untuk sementara waktu 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 InitializeComponent panggilan metode), tetapi Images koleksi diisi nanti dalam GetItemsAsync metode .

Menambahkan tombol hapus

  1. Di MainPage.xaml, temukan CommandBar MainCommandBar bernama 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 ini Click 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 DeleteSelectedImage metode .

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

    Metode ini hanya menghapus gambar yang dipilih dari Images koleksi.

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

Catatan

Kode ini hanya menghapus instans ImageFileInfo dari Images koleksi 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 bernama DataTemplateImageGridView_DefaultItemTemplate dan ganti **Height** nilai Grid dan Width kontrol di bagian atas templat.

    Sebelum

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

    Setelah

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

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

Catatan

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

Sebaliknya, default untuk x:Bind adalah satu kali, 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.

Running app with zoom slider showing

Catatan

Untuk tantangan, coba ikat properti UI lain ke properti penggeser Value zoom, atau ke penggeser lain yang Anda tambahkan setelah penggeser zoom. Misalnya, Anda dapat mengikat FontSize properti penggeleksi baru TitleTextBlock 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 kustom ItemSize 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 tombol Paskan ke layar dan ukuran jendela, membuat pengalaman yang lebih halus.

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

Buat properti ItemSize sehingga memperbarui UI

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

    Sebelum:

    public sealed partial class MainPage : Page
    

    Setelah:

    public sealed partial class MainPage : Page, INotifyPropertyChanged
    

    Ini menginformasikan sistem pengikatan yang MainPage memiliki PropertyChanged peristiwa (ditambahkan berikutnya) yang dapat didengarkan pengikatan untuk memperbarui UI.

  2. PropertyChanged Tambahkan peristiwa ke MainPage kelas .

    public event PropertyChangedEventHandler PropertyChanged;
    

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

  3. ItemSize Tambahkan properti dan naikkan PropertyChanged peristiwa di setter-nya.

    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 privat _itemSize . Menggunakan bidang backing seperti ini memungkinkan properti untuk memeriksa apakah nilai baru sama dengan nilai lama sebelum memunculkan peristiwa yang berpotensi tidak perlu PropertyChanged .

    Peristiwa itu sendiri dimunculkan oleh Invoke metode . Tanda tanya memeriksa apakah PropertyChanged peristiwa 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 PropertyChanged tidak null, maka Invoke dipanggil dengan referensi ke sumber peristiwa (halaman itu sendiri, diwakili oleh this kata kunci) dan objek event-args yang menunjukkan nama properti. Dengan info ini, pengikatan satu arah atau dua arah ke ItemSize properti akan diberi tahu tentang perubahan apa pun sehingga mereka dapat memperbarui UI yang terikat.

  4. Di MainPage.xaml, temukan DataTemplate nama ImageGridView_DefaultItemTemplate dan ganti Height nilai Grid dan Width kontrol 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 dan HeightWidth!)

    Sebelum

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

    Setelah

    <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 ItemSize perubahan, Anda harus benar-benar membuat beberapa perubahan. Seperti disebutkan sebelumnya, ItemSize nilai dihitung dari status saat ini dari berbagai kontrol UI, tetapi perhitungan harus dilakukan setiap kali kontrol tersebut berubah status. Untuk melakukan ini, Anda akan menggunakan pengikatan peristiwa sehingga perubahan UI tertentu akan memanggil metode pembantu yang memperbarui ItemSize.

Memperbarui nilai properti ItemSize

  1. Tambahkan metode ke DetermineItemSize 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 SizeChanged peristiwa ke Page elemen .

    Sebelum:

    <Page x:Name="page"
    

    Setelah:

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

    Sebelum:

    <Slider x:Name="ZoomSlider"
    

    Setelah:

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

    Sebelum:

    <ToggleSwitch x:Name="FitScreenToggle"
    

    Setelah:

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

Jalankan aplikasi dan gunakan penggeser zoom dan Paskan ke pengalih 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.

Running app with fit-to-screen enabled

Catatan

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

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 , yang ada DetailPageyang 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 DetailPage

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

    Tip

    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, tombol tersebut akan mengisi nilai dengan nama handler metode default, dan secara otomatis membagi metode yang ditunjukkan pada langkah berikutnya. Anda kemudian dapat menekan F12 untuk menavigasi ke metode di kode belakang.

    Sebelum:

    <GridView x:Name="ImageGridView">
    

    Setelah:

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

    Catatan

    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 hanya menavigasi ke halaman detail, meneruskan item yang diklik, yang merupakan objek yang ImageFileInfo 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 biasa x:Bind yang kita 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 TextBlock titleTextBlock dan kontrol RatingControl setelahnya, dan perbarui ekspresinya x:Bind untuk menyertakan Mode=TwoWay.

    Sebelum:

    <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 INotifyPropertyChanged implementasi di ImageFileInfo kelas . 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 mempengaruhi 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.

Effect sliders with default label values

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

Mengikat label effect-slider dan memformat nilai untuk tampilan

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

    Sebelum:

    <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 halaman di belakang atau x:DataType jenis jika Anda berada dalam templat data. Dalam hal ini, metode ini adalah metode .NET ToString yang akrab, yang diakses melalui properti item halaman, dan kemudian melalui Exposure properti item. (Ini menggambarkan bagaimana Anda dapat mengikat metode dan properti yang sangat bersarang dalam rantai koneksi.)

    Pengikatan fungsi adalah cara ideal untuk memformat nilai untuk ditampilkan karena Anda dapat meneruskan sumber pengikatan lain sebagai argumen metode, dan ekspresi pengikatan akan mendengarkan perubahan pada nilai tersebut seperti yang diharapkan 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 menimbulkan PropertyChanged peristiwa. Dalam hal ini, setiap perubahan pada nilai properti akan menyebabkan x:Bind ekspresi memanggil ToString dengan nilai baru lalu memperbarui UI dengan hasilnya.

  2. Lakukan hal yang sama untuk TextBlocklabel yang memberi label 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.

Effect sliders with working labels

Kesimpulan

Tutorial ini telah memberi Anda rasa pengikatan data dan menunjukkan beberapa fungsionalitas yang tersedia. Satu kata hati-hati sebelum kami membungkus: tidak semuanya 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 metodenya ChangeView . Dalam hal ini, kami menggunakan penanganan aktivitas konvensional untuk menjaga ScrollViewer penggeser zoom dan tetap sinkron; lihat ZoomSlider_ValueChanged metode dan MainImageScroll_ViewChanged untuk DetailPage 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 ImageFileInfo.ImageTitle properti . Properti ini (dan ImageRating properti) sedikit berbeda dari ItemSize properti yang Anda buat di Bagian 4 karena nilai disimpan dalam metadata file (diekspos melalui ImageProperties jenis) alih-alih di bidang. Selain itu, ImageTitle mengembalikan ImageName nilai (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 ImageProperties.Title properti lalu memanggil SavePropertiesAsync untuk menulis nilai baru ke file. (Ini adalah metode asinkron, tetapi kami tidak dapat menggunakan await kata kunci dalam properti - dan Anda tidak ingin karena getter dan setter properti harus segera selesai. Jadi sebagai gantinya, Anda akan memanggil metode dan mengabaikan objek yang Task dikembalikannya.)

Melaju lebih jauh

Sekarang setelah Anda menyelesaikan lab ini, Anda memiliki cukup pengetahuan yang mengikat mengatasi masalah Anda 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 info yang Anda butuhkan dalam tutorial ini, tetapi jika Anda membutuhkan lebih banyak panduan, dokumen pengikatan data hanya dengan sekali klik. Mulai di sini: