Bagikan melalui


Pengikatan data Windows secara mendalam

Artikel ini menjelaskan fitur pengikatan data WinUI menggunakan API di namespace Microsoft.UI.Xaml.Data.

Nota

Topik ini menjelaskan fitur pengikatan data secara rinci. Untuk pengenalan singkat dan praktis, lihat Gambaran umum pengikatan data.

API penting

Pendahuluan

Pengikatan data adalah teknik yang memungkinkan UI aplikasi Anda menampilkan dan menyinkronkan data secara efisien. Dengan memisahkan kekhawatiran data dari kekhawatiran UI, ini menyederhanakan desain aplikasi, meningkatkan keterbacaan, dan meningkatkan pemeliharaan.

Anda dapat menggunakan pengikatan data untuk hanya menampilkan nilai dari sumber data saat antarmuka pengguna pertama kali ditampilkan, tetapi tidak merespons perubahan dalam nilai tersebut. Mode pengikatan ini disebut satu kali, dan berfungsi dengan baik untuk nilai yang tidak berubah selama run-time. Atau, Anda dapat memilih untuk "mengamati" nilai dan memperbarui UI saat berubah. Mode ini disebut satu arah, dan berfungsi dengan baik untuk data baca-saja. Pada akhirnya, Anda dapat memilih untuk mengamati dan memperbarui, sehingga perubahan yang dilakukan pengguna pada nilai di UI secara otomatis didorong kembali ke sumber data. Mode ini disebut dua arah, dan berfungsi dengan baik untuk data baca-tulis. Berikut adalah beberapa contohnya.

  • Anda dapat menggunakan mode satu kali untuk mengikat Gambar ke foto pengguna saat ini.
  • Anda dapat menggunakan mode satu arah untuk mengikat ListView ke kumpulan artikel berita real time yang dikelompokkan menurut bagian surat kabar.
  • Anda dapat menggunakan mode dua arah untuk mengikat TextBox ke nama pelanggan dalam formulir.

Terlepas dari mode, ada dua jenis pengikatan, dan Anda biasanya mendeklarasikan keduanya dalam markup UI. Anda dapat memilih untuk menggunakan ekstensi markup {x:Bind} atau ekstensi markup {Binding}. Anda bahkan dapat menggunakan campuran keduanya di aplikasi yang sama—bahkan pada elemen UI yang sama. {x:Bind} baru di UWP untuk Windows 10 dan memiliki performa yang lebih baik. Semua detail yang dijelaskan dalam topik ini berlaku untuk kedua jenis pengikatan kecuali kami secara eksplisit mengatakan sebaliknya.

Aplikasi sampel UWP yang memperlihatkan {x:Bind}

Aplikasi sampel UWP yang menggambarkan {Binding}

Setiap pengikatan melibatkan potongan-potongan ini

  • Sumber pengikatan. Sumber ini menyediakan data untuk pengikatan. Ini bisa menjadi instans kelas apa pun yang memiliki anggota yang nilainya ingin Anda tampilkan di UI Anda.
  • Target pengikatan. Target ini adalah DependencyProperty dari FrameworkElement di UI Anda yang menampilkan data.
  • Objek pengikatan. Objek ini mentransfer nilai data dari sumber ke target, dan secara opsional dari target kembali ke sumber. Objek pengikatan dibuat pada waktu pemuatan XAML dari ekstensi markup {x:Bind} atau {Binding} Anda.

Di bagian berikut, Anda melihat lebih dekat sumber pengikatan, target pengikatan, dan objek pengikatan. Bagian-bagian terkait satu sama lain dengan contoh pengikatan konten tombol ke properti string bernama NextButtonText, yang termasuk dalam kelas bernama HostViewModel.

Sumber pengikatan

Berikut adalah implementasi dasar kelas yang dapat Anda gunakan sebagai sumber pengikatan.

public class HostViewModel
{
    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText { get; set; }
}

Implementasi HostViewModel, dan propertinya NextButtonText, hanya berfungsi untuk pengikatan satu kali. Tetapi pengikatan satu arah dan dua arah sangat umum. Dalam jenis pengikatan tersebut, UI secara otomatis memperbarui sebagai respons terhadap perubahan nilai data sumber pengikatan. Agar pengikatan semacam itu berfungsi dengan benar, Anda perlu membuat sumber pengikatan Anda dapat diamati ke objek pengikatan. Jadi dalam contoh kami, jika Anda ingin mengikat satu arah atau dua arah ke properti NextButtonText, maka setiap perubahan yang terjadi pada run-time (waktu proses) terhadap nilai dari properti tersebut perlu terlihat oleh objek pengikatan.

Salah satu cara untuk melakukannya adalah dengan memperoleh kelas yang mewakili sumber pengikatan Anda dari DependencyObject, dan mengekspos nilai data melalui DependencyProperty*. Itulah bagaimana FrameworkElement menjadi dapat diamati. A FrameworkElement adalah sumber pengikatan yang baik langsung dari kotak.

Cara yang lebih ringan untuk membuat kelas dapat diamati—dan yang diperlukan untuk kelas yang sudah memiliki kelas dasar—adalah dengan mengimplementasikan System.ComponentModel.INotifyPropertyChanged. Pendekatan ini melibatkan penerapan satu peristiwa bernama PropertyChanged. Contoh penggunaan HostViewModel diperlihatkan dalam kode berikut.

...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return nextButtonText; }
        set
        {
            nextButtonText = value;
            OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

NextButtonText Sekarang properti dapat diamati. Saat Anda menulis pengikatan satu arah atau dua arah ke properti tersebut (kami akan menunjukkan bagaimana nanti), objek pengikatan yang dihasilkan berlangganan peristiwa tersebut PropertyChanged . Ketika peristiwa tersebut dinaikkan, handler objek pengikatan menerima argumen yang berisi nama properti yang berubah. Itulah cara objek pengikatan mengetahui nilai properti mana yang akan dibaca lagi.

Sehingga Anda tidak perlu menerapkan pola yang ditampilkan sebelumnya beberapa kali, jika Anda menggunakan C#, Anda dapat memperoleh dari BindableBase kelas dasar yang akan Anda temukan di sampel QuizGame (di folder "Umum"). Berikut adalah contoh tampilannya.

public class HostViewModel : BindableBase
{
    private string nextButtonText;

    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return nextButtonText; }
        set { SetProperty(ref nextButtonText, value); }
    }
}

Menaikkan PropertyChanged peristiwa dengan argumen String.Empty atau null menunjukkan bahwa semua properti non-pengindeks pada objek harus dibaca ulang. Anda dapat menaikkan peristiwa untuk menunjukkan bahwa properti pengindeks pada objek telah berubah dengan menggunakan argumen "Item[indexer]" untuk pengindeks tertentu (di mana pengindeks adalah nilai indeks), atau nilai "Item[]" untuk semua pengindeks.

Anda dapat memperlakukan sumber pengikatan baik sebagai objek tunggal yang propertinya berisi data, atau sebagai kumpulan objek. Dalam kode C#, Anda dapat mengikat satu kali ke objek yang mengimplementasikan Daftar<T> untuk menampilkan koleksi yang tidak berubah pada run-time. Untuk koleksi yang dapat diamati (mengamati kapan item ditambahkan ke dan dihapus dari koleksi), ikat satu arah ke ObservableCollection<T> sebagai gantinya. Untuk mengikat kelas koleksi Anda sendiri, gunakan panduan dalam tabel berikut.

Scenario C# (CLR) C++/WinRT
Ikat ke objek. Bisa menjadi objek apa pun. Bisa menjadi objek apa pun.
Mendapatkan pemberitahuan perubahan properti dari objek terikat. Objek harus mengimplementasikan INotifyPropertyChanged. Objek harus mengimplementasikan INotifyPropertyChanged.
Ikat ke koleksi. Daftar<T> IVector dari IInspectable, atau IBindableObservableVector. Lihat kontrol item XAML; ikat ke koleksi dan Koleksi C++/WinRTdengan C++/WinRT.
Dapatkan pemberitahuan perubahan koleksi dari koleksi terikat. ObservableCollection<T> IObservableVector dari IInspectable. Misalnya, winrt::single_threaded_observable_vector<T>.
Terapkan koleksi yang mendukung pengikatan. Perluas Daftar<T> atau terapkan IList,Objek<IList>, IEnumerable, atau IEnumerable<Object>. Pengikatan ke generik IList<T> dan IEnumerable<T> tidak didukung. Terapkan IVector dari IInspectable. Lihat kontrol item XAML; ikat ke koleksi dan Koleksi C++/WinRTdengan C++/WinRT.
Terapkan koleksi yang mendukung pemberitahuan perubahan koleksi. Perluas ObservableCollection<T> atau terapkan IList (non-generik) dan INotifyCollectionChanged. Terapkan IObservableVector dari IInspectable, atau IBindableObservableVector.
Terapkan koleksi yang mendukung pemuatan bertahap. Perluas ObservableCollection<T> atau terapkan IList (non-generik) dan INotifyCollectionChanged. Selain itu, terapkan ISupportIncrementalLoading. Terapkan IObservableVector dari IInspectable, atau IBindableObservableVector. Selain itu, terapkan ISupportIncrementalLoading

Anda dapat mengikat kontrol daftar untuk sumber data besar secara sewenang-wenang, dan masih mencapai performa tinggi, dengan menggunakan pemuatan inkremental. Misalnya, Anda dapat mengikat kontrol daftar ke hasil kueri gambar Bing tanpa harus memuat semua hasil sekaligus. Sebagai gantinya, Anda hanya memuat beberapa hasil segera, dan memuat hasil tambahan sesuai kebutuhan. Untuk mendukung pemuatan bertahap, Anda harus menerapkan ISupportIncrementalLoading pada sumber data yang mendukung pemberitahuan perubahan pengumpulan. Saat mesin pengikatan data meminta lebih banyak data, sumber data Anda harus membuat permintaan yang sesuai, mengintegrasikan hasilnya, lalu mengirim pemberitahuan yang sesuai untuk memperbarui UI.

Target pengikatan

Dalam dua contoh berikut, Button.Content properti adalah target pengikatan. Nilainya diatur ke ekstensi markup yang mendeklarasikan objek pengikatan. Contoh pertama memperlihatkan {x:Bind}, dan contoh kedua memperlihatkan {Binding}. Mendeklarasikan pengikatan dalam markup adalah kasus umum karena nyaman, dapat dibaca, dan dapat digunakan. Tetapi jika perlu, Anda dapat menghindari markup dan secara imperatif (terprogram) membuat instans kelas Pengikatan sebagai gantinya.

<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />

Jika Anda menggunakan C++/WinRT, maka Anda perlu menambahkan atribut BindableAttribute ke kelas runtime apa pun yang ingin Anda gunakan ekstensi markup {Binding} .

Penting

Jika Anda menggunakan C++/WinRT, atribut BindableAttribute tersedia dengan Windows App SDK. Tanpa atribut tersebut, Anda perlu mengimplementasikan antarmuka ICustomPropertyProvider dan ICustomProperty agar dapat menggunakan ekstensi markup {Binding} .

Objek pengikatan dideklarasikan menggunakan {x:Bind}

Sebelum menulis markup {x:Bind} , Anda perlu mengekspos kelas sumber pengikatan dari kelas yang mewakili halaman markup Anda. Tambahkan properti (jenis HostViewModel dalam kasus ini) ke kelas jendela Anda MainWindow .

namespace DataBindingInDepth
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            ViewModel = new HostViewModel();
        }
    
        public HostViewModel ViewModel { get; set; }
    }
}

Setelah menambahkan properti, Anda dapat melihat lebih dekat markup yang mendeklarasikan objek pengikatan. Contoh berikut menggunakan target pengikatan yang sama Button.Content dengan yang Anda lihat di bagian "Target pengikatan" sebelumnya. Ini menunjukkan target pengikatan yang terikat ke properti HostViewModel.NextButtonText.

<!-- MainWindow.xaml -->
<Window x:Class="DataBindingInDepth.MainWindow" ... >
    <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Window>

Perhatikan nilai yang Anda tentukan untuk Path. Jendela menafsirkan nilai ini dalam konteksnya sendiri. Dalam hal ini, jalur dimulai dengan merujuk properti ViewModel yang baru saja Anda tambahkan ke MainWindow halaman. Properti tersebut mengembalikan instance HostViewModel, sehingga Anda dapat menggunakan operator dot pada objek tersebut untuk mengakses properti HostViewModel.NextButtonText. Anda menentukan Mode untuk mengambil alih default {x:Bind} yang hanya terjadi sekali.

Properti Jalur mendukung berbagai opsi sintaks untuk mengikat properti berlapis, properti terlampir, serta bilangan bulat dan pengindeks string. Untuk informasi selengkapnya, lihat Sintaks jalur properti. Pengikatan ke pengindeks string memberi Anda efek pengikatan ke properti dinamis tanpa harus menerapkan ICustomPropertyProvider. Untuk pengaturan lain, lihat ekstensi markup {x:Bind}.

Untuk mengilustrasikan bahwa HostViewModel.NextButtonText properti dapat diamati, tambahkan Click penanganan aktivitas ke tombol , dan perbarui nilai HostViewModel.NextButtonText. Buat, jalankan, dan klik tombol untuk melihat nilai pembaruan tombol Content .

// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    ViewModel.NextButtonText = "Updated Next button text";
}

Nota

Perubahan TextBox.Text dikirim ke sumber yang terikat dua arah ketika TextBox kehilangan fokus, bukan setelah setiap kali pengguna menekan tombol.

DataTemplate dan x:DataType

Di dalam DataTemplate (apakah Anda menggunakannya sebagai templat item, templat konten, atau templat header), nilai Path tidak ditafsirkan dalam konteks jendela. Sebaliknya, ini berfungsi dalam konteks objek data yang Anda templatkan. Saat Anda menggunakan {x:Bind} dalam templat data, Anda dapat memvalidasi pengikatannya pada waktu kompilasi dan menghasilkan kode yang efisien untuk mereka. Untuk melakukan ini, DataTemplate perlu mendeklarasikan jenis objek datanya dengan menggunakan x:DataType. Contoh berikut dapat digunakan sebagai ItemTemplate kontrol item yang terikat ke kumpulan SampleDataGroup objek.

<DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{x:Bind Title}"/>
      <TextBlock Text="{x:Bind Description}"/>
    </StackPanel>
  </DataTemplate>

Objek yang ditik lemah di Jalur Anda

Misalkan Anda memiliki jenis bernama SampleDataGroup yang mengimplementasikan properti string bernama Title. Anda juga memiliki properti MainWindow.SampleDataGroupAsObject yang berjenis object, tetapi sebenarnya mengembalikan sebuah instans SampleDataGroup. Pengikatan <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> menghasilkan kesalahan kompilasi karena properti Title tidak ditemukan pada tipe object. Untuk memperbaiki kesalahan ini, tambahkan cast ke sintaks Anda Path seperti ini: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Berikut adalah contoh lain di mana Element dinyatakan sebagai object tetapi sebenarnya adalah TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>. Cast memperbaiki masalah: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.

Jika data Anda dimuat secara asinkron

Kelas parsial untuk jendela Anda menghasilkan kode untuk mendukung {x:Bind} pada saat kompilasi. Anda dapat menemukan file-file ini di folder Anda obj , dengan nama seperti (untuk C#) <view name>.g.cs. Kode yang dihasilkan mencakup handler untuk peristiwa Pemuatan jendela Anda. Handler tersebut memanggil metode Initialize pada kelas yang telah dihasilkan yang merepresentasikan pengikatan pada jendela Anda. Initialize memanggil Update untuk mulai memindahkan data antara sumber ikatan dan target. Loading dinaikkan tepat sebelum lulus pengukuran pertama dari jendela atau kontrol pengguna. Jika data Anda dimuat secara asinkron, data mungkin tidak siap pada saat Initialize dipanggil. Setelah memuat data, Anda dapat memaksa pengikatan satu kali untuk diinisialisasi dengan memanggil this.Bindings.Update();. Jika Anda hanya memerlukan pengikatan satu kali untuk data yang dimuat secara asinkron, jauh lebih murah untuk menginisialisasinya dengan cara ini daripada memiliki pengikatan satu arah dan mendengarkan perubahan. Jika data Anda tidak mengalami perubahan mencolok dan kemungkinan akan diperbarui sebagai bagian dari tindakan tertentu, Anda dapat membuat pengikatan satu kali dan memaksa pembaruan manual kapan saja dengan panggilan ke Update.

Nota

{x:Bind} tidak cocok untuk skenario yang diikat secara dinamis, seperti menavigasi struktur dictionary dari objek JSON, atau duck typing. "Pengetikan bebek" adalah bentuk pengetikan yang lemah berdasarkan kecocokan leksikal pada nama properti (seperti dalam, "jika berjalan, berenang, dan kuktek seperti bebek, maka itu adalah bebek"). Dengan pengetikan bebek, pengikatan ke Age properti akan sama-sama puas dengan objek Person atau Wine (dengan asumsi bahwa jenis tersebut masing-masing memiliki Age properti). Untuk skenario ini, gunakan {Binding} ekstensi markup.

Objek pengikatan dideklarasikan dengan menggunakan {Binding}

Jika Anda menggunakan C++/WinRT, tambahkan atribut BindableAttribute ke kelas runtime apa pun yang ingin Anda ikat saat Anda menggunakan ekstensi markup {Binding} . Untuk menggunakan {x:Bind}, Anda tidak memerlukan atribut tersebut.

// HostViewModel.idl
// Add this attribute:
[Microsoft.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
    HostViewModel();
    String NextButtonText;
}

Penting

Jika Anda menggunakan C++/WinRT, atribut BindableAttribute tersedia dengan Windows App SDK. Tanpa atribut tersebut, Anda perlu mengimplementasikan antarmuka ICustomPropertyProvider dan ICustomProperty agar dapat menggunakan ekstensi markup {Binding} .

Secara default, {Binding} mengasumsikan bahwa Anda mengikat ke DataContext dari jendela markup Anda. Jadi, atur jendela DataContext Anda menjadi instans kelas sumber pengikatan Anda (jenis HostViewModel dalam kasus ini). Contoh berikut menunjukkan markup yang mendeklarasikan objek pengikatan. Ini menggunakan target pengikatan Button.Content yang sama seperti di bagian "Target pengikatan" sebelumnya, dan mengikat ke properti HostViewModel.NextButtonText.

<Window xmlns:viewmodel="using:DataBindingInDepth" ... >
    <Window.DataContext>
        <viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
    </Window.DataContext>
    ...
    <Button Content="{Binding Path=NextButtonText}" ... />
</Window>
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    viewModelInDataContext.NextButtonText = "Updated Next button text";
}

Perhatikan nilai yang ditentukan untuk Path. DataContext dari jendela menginterpretasikan nilai ini, yang dalam contoh ini disetel ke instance dari HostViewModel. Jalur mereferensikan HostViewModel.NextButtonText properti . Anda dapat menghilangkan Mode, karena pengikatan satu arah default pada {Binding} berfungsi di sini.

Nilai default DataContext untuk elemen UI adalah nilai yang diwariskan dari induknya. Anda dapat mengganti default tersebut dengan menetapkan DataContext secara eksplisit, yang pada gilirannya akan diwarisi oleh anak secara default. Mengatur DataContext secara eksplisit pada elemen berguna ketika Anda ingin memiliki beberapa pengikatan yang menggunakan sumber yang sama.

Objek pengikatan memiliki Source properti, yang default ke DataContext dari elemen UI tempat pengikatan dideklarasikan. Anda dapat mengambil alih default ini dengan mengatur Source, , RelativeSourceatau ElementName secara eksplisit pada pengikatan (lihat {Binding} untuk detailnya).

Di dalam DataTemplate, DataContext secara otomatis diatur ke objek data yang sedang di-template. Contoh berikut dapat digunakan sebagai ItemTemplate kontrol item yang terikat ke kumpulan jenis apa pun yang memiliki properti string bernama Title dan Description.

<DataTemplate x:Key="SimpleItemTemplate">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{Binding Title}"/>
      <TextBlock Text="{Binding Description"/>
    </StackPanel>
  </DataTemplate>

Nota

Secara default, perubahan pada TextBox.Text dikirim ke sumber terikat dua arah saat TextBox kehilangan fokus. Untuk menyebabkan perubahan dikirim setelah setiap penekanan kunci pengguna, atur UpdateSourceTrigger ke PropertyChanged pada pengikatan dalam markup. Anda juga dapat sepenuhnya mengontrol kapan perubahan dikirim ke sumber dengan mengatur UpdateSourceTrigger ke Explicit. Anda kemudian menangani peristiwa di kotak teks (biasanya TextBox.TextChanged), panggil GetBindingExpression pada target untuk mendapatkan objek BindingExpression , dan akhirnya memanggil BindingExpression.UpdateSource untuk memperbarui sumber data secara terprogram.

Properti Jalur mendukung berbagai opsi sintaks untuk mengikat properti berlapis, properti terlampir, serta bilangan bulat dan pengindeks string. Untuk informasi selengkapnya, lihat Sintaks jalur properti. Pengikatan ke pengindeks string memberi Anda efek pengikatan ke properti dinamis tanpa harus menerapkan ICustomPropertyProvider. Properti ElementName berguna untuk pengikatan elemen-ke-elemen. Properti RelativeSource memiliki beberapa kegunaan, salah satunya sebagai alternatif yang lebih kuat untuk pengikatan templat di dalam ControlTemplate. Untuk pengaturan lain, lihat ekstensi markup {Binding} dan kelas Pengikatan .

Bagaimana jika sumber dan target bukan jenis yang sama?

Jika Anda ingin mengontrol visibilitas elemen UI berdasarkan nilai properti boolean, atau jika Anda ingin merender elemen UI dengan warna yang merupakan fungsi dari rentang atau tren nilai numerik, atau jika Anda ingin menampilkan nilai tanggal dan/atau waktu dalam properti elemen UI yang mengharapkan string, maka Anda perlu mengonversi nilai dari satu jenis ke jenis lainnya. Ada kasus di mana solusi yang tepat adalah mengekspos properti lain dari jenis yang tepat dari kelas sumber pengikatan Anda, dan menjaga logika konversi tetap terenkapsulasi dan dapat diuji di sana. Tetapi solusi itu tidak fleksibel atau dapat diskalakan ketika Anda memiliki sejumlah besar atau kombinasi besar properti sumber dan target. Dalam hal ini, Anda memiliki beberapa opsi:

  • Jika menggunakan {x:Bind} maka Anda dapat mengikat langsung ke fungsi untuk melakukan konversi tersebut
  • Atau Anda dapat menentukan pengonversi nilai yang merupakan objek yang dirancang untuk melakukan konversi

Pengonversi Nilai

Berikut adalah pengonversi nilai, cocok untuk pengikatan satu kali atau satu arah, yang mengonversi nilai DateTime menjadi nilai yang string berisi bulan. Kelas mengimplementasikan IValueConverter.

public class DateToStringConverter : IValueConverter
{
    // Define the Convert method to convert a DateTime value to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        // value is the data from the source object.
        DateTime thisDate = (DateTime)value;
        int monthNum = thisDate.Month;
        string month;
        switch (monthNum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;
    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Dan berikut adalah cara Anda menggunakan pengonversi nilai tersebut dalam markup objek pengikatan Anda.

<UserControl.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0" 
  Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0" 
  Text="{Binding Month, Converter={StaticResource Converter1}}"/>

Mesin pengikatan memanggil metode Konversi dan Konversi Balik jika parameter Converter ditentukan untuk pengikatan. Ketika data diteruskan dari sumber, mesin pengikatan memanggil Convert dan meneruskan data yang dikembalikan ke target. Ketika data diteruskan dari target (untuk pengikatan dua arah), mesin pengikatan memanggil ConvertBack dan meneruskan data yang dikembalikan ke sumbernya.

Pengonversi juga memiliki parameter opsional: ConverterLanguage, yang memungkinkan menentukan bahasa yang akan digunakan dalam konversi, dan ConverterParameter, yang memungkinkan melewati parameter untuk logika konversi. Untuk contoh yang menggunakan parameter pengonversi, lihat IValueConverter.

Nota

Jika ada kesalahan dalam konversi, jangan melemparkan pengecualian. Sebagai gantinya, kembalikan DependencyProperty.UnsetValue, yang akan menghentikan transfer data.

Untuk menampilkan nilai default yang akan digunakan setiap kali sumber pengikatan tidak dapat diselesaikan, atur FallbackValue properti pada objek pengikatan dalam markup. Ini berguna untuk menangani kesalahan konversi dan pemformatan. Ini juga berguna untuk mengikat properti sumber yang mungkin tidak ada pada semua objek dalam koleksi terikat jenis heterogen.

Jika Anda mengikat kontrol teks ke nilai yang bukan string, mesin pengikatan data akan mengonversi nilai menjadi string. Jika nilai adalah jenis referensi, mesin pengikatan data akan mengambil nilai string dengan memanggil ICustomPropertyProvider.GetStringRepresentation atau IStringable.ToString jika tersedia, dan jika tidak akan memanggil Object.ToString. Namun, perhatikan bahwa mesin pengikatan akan mengabaikan implementasi apa pun ToString yang menyembunyikan implementasi kelas dasar. Implementasi subkelas harus mengambil alih metode kelas ToString dasar sebagai gantinya. Demikian pula, dalam bahasa asli, semua objek terkelola tampaknya mengimplementasikan ICustomPropertyProvider dan IStringable. Namun, semua panggilan ke GetStringRepresentation dan IStringable.ToString dirutekan ke Object.ToString atau penimpaan metode tersebut, dan tidak pernah ke implementasi baru ToString yang menyembunyikan implementasi kelas dasar.

Nota

Windows Community Toolkit menyediakan BoolToVisibilityConverter. Pengonversi memetakan true ke Visible nilai enumerasi dan false ke Collapsed sehingga Anda dapat mengikat Visibility properti ke boolean tanpa membuat pengonversi. Untuk menggunakan pengonversi, proyek Anda harus menambahkan paket CommunityToolkit.WinUI.Converters NuGet.

Pengikatan fungsi di {x:Bind}

{x:Bind} memungkinkan langkah terakhir dalam jalur pengikatan menjadi fungsi. Gunakan fitur ini untuk melakukan konversi atau membuat pengikatan yang bergantung pada lebih dari satu properti. Untuk informasi selengkapnya, lihat Fungsi di x:Bind.

Pengikatan elemen-ke-elemen

Anda dapat mengikat properti dari satu elemen XAML ke properti elemen XAML lain. Berikut adalah contoh bagaimana pengikatan tersebut terlihat dalam markup.

<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />

Kamus sumber daya dengan {x:Bind}

Ekstensi markup {x:Bind} bergantung pada pembuatan kode, sehingga memerlukan file code-behind yang berisi konstruktor yang memanggil InitializeComponent (untuk menginisialisasi kode yang dihasilkan). Untuk menggunakan kembali kamus sumber daya, buat jenisnya (sehingga InitializeComponent dipanggil) alih-alih mereferensikan nama filenya. Berikut adalah contoh apa yang harus dilakukan jika Anda memiliki kamus sumber daya yang sudah ada dan ingin Anda gunakan {x:Bind} di dalamnya.

<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI.Xaml.Data;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
    }
}
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Window.Resources>
        <ResourceDictionary>
            .... 
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
</Window>

Mencampur {x:Bind} dan {Binding} dalam Gaya yang Dapat Digunakan Kembali

Contoh sebelumnya menunjukkan cara menggunakan {x:Bind} dalam DataTemplates. Anda juga dapat membuat Gaya yang dapat digunakan kembali yang menggabungkan ekstensi markup {x:Bind} dan {Binding} . Kombinasi ini berguna ketika Anda ingin mengikat beberapa properti ke nilai yang diketahui waktu kompilasi dengan menggunakan {x:Bind} dan properti lain untuk nilai DataContext runtime dengan menggunakan {Binding}.

Contoh berikut menunjukkan cara membuat gaya Tombol yang dapat digunakan kembali yang menggunakan kedua pendekatan pengikatan:

TemplatesResourceDictionary.xaml

<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <!-- DataTemplate using x:Bind -->
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
    
    <!-- Style that mixes x:Bind and Binding -->
    <Style x:Key="CustomButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
        <Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Margin" Value="4"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="RootBorder"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="4">
                        <StackPanel Orientation="Horizontal" 
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                            <!-- x:Bind to a static property or page-level property -->
                            <Ellipse Width="8" Height="8" 
                                     Fill="{x:Bind DefaultIndicatorBrush}" 
                                     Margin="0,0,8,0"/>
                            <!-- Binding to DataContext -->
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              Foreground="{TemplateBinding Foreground}"
                                              FontSize="{TemplateBinding FontSize}"/>
                        </StackPanel>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <VisualState.Setters>
                                        <!-- Binding to DataContext for hover color -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{Binding ButtonHoverBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <VisualState.Setters>
                                        <!-- x:Bind to a compile-time known resource -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{x:Bind DefaultPressedBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
        
        // Properties for x:Bind - these are compile-time bound
        public SolidColorBrush DefaultIndicatorBrush { get; } = 
            new SolidColorBrush(Colors.Green);
            
        public SolidColorBrush DefaultPressedBrush { get; } = 
            new SolidColorBrush(Colors.DarkGray);
    }
}

Penggunaan di MainWindow.xaml dengan ViewModel yang menyediakan nilai runtime:

<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <Grid.DataContext>
            <examplenamespace:ButtonThemeViewModel/>
        </Grid.DataContext>
        
        <StackPanel Margin="20">
            <!-- These buttons use the mixed binding style -->
            <Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
            <Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
        </StackPanel>
    </Grid>
</Window>

ButtonThemeViewModel.cs (DataContext yang menyediakan nilai pengikatan runtime):

using System.ComponentModel;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;

namespace ExampleNamespace
{
    public class ButtonThemeViewModel : INotifyPropertyChanged
    {
        private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
        private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
        private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);

        public SolidColorBrush ButtonBackgroundBrush
        {
            get => _buttonBackgroundBrush;
            set
            {
                _buttonBackgroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
            }
        }

        public SolidColorBrush ButtonForegroundBrush
        {
            get => _buttonForegroundBrush;
            set
            {
                _buttonForegroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
            }
        }

        public SolidColorBrush ButtonHoverBrush
        {
            get => _buttonHoverBrush;
            set
            {
                _buttonHoverBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Dalam contoh ini:

  • {Binding} digunakan untuk properti yang bergantung pada DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)
  • {x:Bind} digunakan untuk properti yang diketahui waktu kompilasi dan milik ResourceDictionary itu sendiri (DefaultIndicatorBrush, DefaultPressedBrush)
  • Gaya dapat digunakan kembali dan Anda dapat menerapkannya ke Tombol apa pun
  • Tema runtime dimungkinkan melalui DataContext sambil tetap mendapat manfaat dari {x:Bind} performa untuk elemen statis

Pengikatan peristiwa dan ICommand

{x:Bind} mendukung fitur yang disebut pengikatan peristiwa. Dengan fitur ini, Anda dapat menentukan handler untuk suatu acara dengan menggunakan pengikatan. Fitur ini adalah opsi tambahan untuk menangani peristiwa, selain menangani peristiwa dengan metode dalam file code-behind. Misalkan Anda memiliki pengendali acara ListViewDoubleTapped di kelas MainWindow Anda.

public sealed partial class MainWindow : Window
{
    ...
    public void ListViewDoubleTapped()
    {
        // Handle double-tapped logic
    }
}

Anda dapat mengikat peristiwa DoubleTapped ListView ke metode di MainWindow seperti ini.

<ListView DoubleTapped="{x:Bind ListViewDoubleTapped}" />

Anda tidak dapat menggunakan metode yang kelebihan beban untuk menangani peristiwa dengan teknik ini. Selain itu, jika metode yang menangani peristiwa memiliki parameter, maka semuanya harus dapat ditetapkan dari jenis semua parameter peristiwa. Dalam hal ini, ListViewDoubleTapped tidak kelebihan beban dan tidak memiliki parameter (tetapi masih akan valid bahkan jika membutuhkan dua object parameter).

Teknik pengikatan peristiwa mirip dengan mengimplementasikan dan mengkonsumsi perintah. Perintah adalah properti yang mengembalikan objek yang mengimplementasikan antarmuka ICommand . {x:Bind} dan {Binding} berfungsi dengan perintah. Sehingga Anda tidak perlu menerapkan pola perintah beberapa kali, Anda dapat menggunakan DelegateCommand kelas pembantu yang Anda temukan di sampel QuizGame UWP (di folder "Umum").

Mengikat ke kumpulan folder atau file

Anda dapat menggunakan API di namespace Windows.Storage untuk mengambil folder dan data file di aplikasi Windows App SDK yang dipaketkan. Namun, berbagai metode GetFilesAsync, GetFoldersAsync, dan GetItemsAsync tidak mengembalikan nilai yang cocok untuk pemautan ke kontrol daftar. Sebagai gantinya, Anda harus mengikat nilai pengembalian metode GetVirtualizedFilesVector, GetVirtualizedFoldersVector, dan GetVirtualizedItemsVector dari kelas FileInformationFactory . Contoh kode berikut dari sampel UWP StorageDataSource dan GetVirtualizedFilesVector menunjukkan pola penggunaan umum. Ingatlah untuk mendeklarasikan kemampuan gambarLibrary dalam manifes paket aplikasi Anda, dan konfirmasikan bahwa ada gambar di folder pustaka Gambar Anda.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var library = Windows.Storage.KnownFolders.PicturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions();
    queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
    queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;

    var fileQuery = library.CreateFileQueryWithOptions(queryOptions);

    var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
        fileQuery,
        Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
        190,
        Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
        false
        );

    var dataSource = fif.GetVirtualizedFilesVector();
    this.PicturesListView.ItemsSource = dataSource;
}

Anda biasanya menggunakan pendekatan ini untuk membuat tampilan baca-saja info file dan folder. Anda dapat membuat pengikatan dua arah ke properti file dan folder, misalnya untuk memungkinkan pengguna menilai lagu dalam tampilan musik. Namun, perubahan apa pun tidak bertahan sampai Anda memanggil metode yang sesuai SavePropertiesAsync (misalnya, MusicProperties.SavePropertiesAsync). Anda harus menerapkan perubahan saat item kehilangan fokus karena tindakan ini memicu reset pilihan.

Perhatikan bahwa pengikatan dua arah menggunakan teknik ini hanya berfungsi dengan lokasi terindeks, seperti Musik. Anda dapat menentukan apakah lokasi diindeks dengan memanggil metode FolderInformation.GetIndexedStateAsync .

Perhatikan juga bahwa vektor virtual dapat kembali null untuk beberapa item sebelum mengisi nilainya. Misalnya, Anda harus memeriksa null sebelum menggunakan nilai SelectedItem dari kontrol daftar yang terikat ke vektor virtual, atau menggunakan SelectedIndex sebagai gantinya.

Pengikatan ke data yang dikelompokkan menurut kunci

Jika Anda mengambil koleksi datar item (buku, misalnya, diwakili oleh BookSku kelas) dan Anda mengelompokkan item dengan menggunakan properti umum sebagai kunci ( BookSku.AuthorName properti , misalnya), maka hasilnya disebut data yang dikelompokkan. Saat Anda mengelompokkan data, data tersebut bukan lagi koleksi datar. Data yang dikelompokkan adalah kumpulan objek grup, di mana setiap objek grup memiliki:

  • kunci, dan
  • kumpulan item yang propertinya cocok dengan kunci tersebut.

Untuk mengambil contoh buku lagi, hasil pengelompokan buku menurut nama penulis menghasilkan kumpulan grup nama penulis di mana setiap grup memiliki:

  • kunci, yang merupakan nama penulis, dan
  • kumpulan BookSku objek yang propertinya AuthorName cocok dengan kunci grup.

Secara umum, untuk menampilkan koleksi, Anda mengikat ItemsSource kontrol item (seperti ListView atau GridView) langsung ke properti yang mengembalikan koleksi. Jika itu adalah koleksi sederhana barang, maka Anda tidak perlu melakukan tindakan khusus. Tetapi jika itu adalah kumpulan objek grup (seperti saat mengikat ke data yang dikelompokkan), maka Anda memerlukan layanan objek perantara yang disebut CollectionViewSource yang berada di antara kontrol item dan sumber pengikatan. Anda mengikat CollectionViewSource ke properti yang mengembalikan data yang dikelompokkan, dan Anda mengikat kontrol item ke CollectionViewSource. Penambahan CollectionViewSource nilai tambahan adalah item saat ini dilacak, sehingga Anda dapat menjaga lebih dari satu kontrol item tetap sinkron dengan mengikat semuanya ke item yang sama CollectionViewSource. Anda juga dapat mengakses item saat ini secara terprogram melalui properti ICollectionView.CurrentItem objek yang dikembalikan oleh properti CollectionViewSource.View .

Untuk mengaktifkan fasilitas pengelompokan CollectionViewSource, atur IsSourceGrouped ke true. Apakah Anda juga perlu mengatur properti ItemsPath bergantung pada cara Anda menulis objek grup Anda. Ada dua cara untuk menulis objek grup: pola "is-a-group", dan pola "has-a-group". Dalam pola "is-a-group", objek grup berasal dari jenis koleksi (misalnya, List<T>), sehingga objek grup sebenarnya adalah grup item. Dengan pola ini Anda tidak perlu mengatur ItemsPath. Dalam pola "has-a-group", objek grup memiliki satu atau beberapa properti dari jenis koleksi (seperti List<T>), sehingga grup "memiliki" grup item dalam bentuk properti (atau beberapa grup item dalam bentuk beberapa properti). Dengan pola ini, Anda perlu mengatur ItemsPath ke nama properti yang berisi grup item.

Contoh berikut mengilustrasikan pola "memiliki-sebuah-grup". Kelas jendela memiliki properti bernama DataContext, yang mengembalikan instans model tampilan kami. CollectionViewSource mengikat ke Authors properti model tampilan (Authors adalah kumpulan objek grup) dan juga menentukan bahwa itu adalah Author.BookSkus properti yang berisi item yang dikelompokkan. Akhirnya, GridView terikat ke CollectionViewSource, dan memiliki gaya grup yang ditentukan sehingga dapat merender item dalam grup.

<Window.Resources>
    <CollectionViewSource
    x:Name="AuthorHasACollectionOfBookSku"
    Source="{x:Bind ViewModel.Authors}"
    IsSourceGrouped="true"
    ItemsPath="BookSkus"/>
</Window.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
    <GridView.GroupStyle>
        <GroupStyle
            HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
    </GridView.GroupStyle>
</GridView>

Anda dapat menerapkan pola "is-a-group" dengan salah satu dari dua cara. Salah satu caranya adalah dengan menulis kelas grup Anda sendiri. Mendapatkan kelas dari List<T> (di mana T adalah jenis item). Contohnya, public class Author : List<BookSku>. Cara kedua adalah menggunakan ekspresi LINQ untuk membuat objek grup secara dinamis (dan kelas grup) dari seperti nilai properti item BookSku . Pendekatan ini—hanya mempertahankan daftar datar item dan mengelompokkannya bersama-sama dengan cepat—adalah tipikal aplikasi yang mengakses data dari layanan cloud. Anda mendapatkan fleksibilitas untuk mengelompokkan buku menurut penulis atau berdasarkan genre (misalnya) tanpa memerlukan kelas grup khusus seperti Penulis dan Genre.

Contoh berikut mengilustrasikan pola "is-a-group" menggunakan LINQ. Kali ini kami mengelompokkan buku berdasarkan genre, ditampilkan dengan nama genre di header grup. Pengelompokan ini ditunjukkan oleh jalur properti "Kunci" dalam referensi ke nilai Kunci grup.

using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;

public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
    get
    {
        if (genres == null)
        {
            genres = from book in bookSkus
                     group book by book.genre into grp
                     orderby grp.Key
                     select grp;
        }
        return genres;
    }
}

Ingatlah bahwa saat menggunakan {x:Bind} dengan templat data, Anda perlu menunjukkan jenis yang terikat dengan mengatur nilai x:DataType. Jika jenisnya generik, maka Anda tidak dapat mengekspresikannya dalam markup sehingga Anda perlu menggunakan {Binding} sebagai gantinya di templat header gaya grup.

    <Grid.Resources>
        <CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
        Source="{x:Bind Genres}"
        IsSourceGrouped="true"/>
    </Grid.Resources>
    <GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
        <GridView.ItemTemplate x:DataType="local:BookTemplate">
            <DataTemplate>
                <TextBlock Text="{x:Bind Title}"/>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Key}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </GridView.GroupStyle>
    </GridView>

Kontrol SemanticZoom adalah cara yang bagus bagi pengguna Anda untuk melihat dan menavigasi data yang dikelompokkan. Aplikasi sampel UWP Bookstore2 mengilustrasikan cara menggunakan SemanticZoom. Di aplikasi tersebut, Anda dapat melihat daftar buku yang dikelompokkan menurut penulis (tampilan yang diperbesar) atau Anda dapat memperkecil untuk melihat daftar lompat penulis (tampilan yang diperkecil). Daftar lompat membeli navigasi yang jauh lebih cepat daripada menggulir daftar buku. Tampilan yang diperbesar dan diperkecil sebenarnya ListView atau GridView kontrol terikat ke tampilan yang sama CollectionViewSource.

Ilustrasi SemanticZoom

Saat Anda mengikat data hierarkis—seperti subkategori dalam kategori—Anda dapat memilih untuk menampilkan tingkat hierarkis di UI Anda dengan serangkaian kontrol item. Pilihan dalam satu kontrol item menentukan konten kontrol item berikutnya. Anda dapat menjaga daftar tetap sinkron dengan mengikat setiap daftar ke CollectionViewSource sendiri dan mengikat CollectionViewSource instans bersama-sama dalam rantai. Penyiapan ini disebut tampilan master/detail atau list/detail. Untuk informasi selengkapnya, lihat Cara mengikat data hierarkis dan membuat tampilan master/detail.

Mendiagnosis dan men-debug masalah pengikatan data

Markup pengikatan Anda berisi nama properti (dan, untuk C#, terkadang bidang dan metode). Jadi ketika Anda mengganti nama properti, Anda juga perlu mengubah pengikatan apa pun yang mereferensikannya. Jika lupa melakukannya, Anda membuat bug pengikatan data, dan aplikasi Anda tidak mengompilasi atau tidak berjalan dengan benar.

Objek pengikatan yang dibuat {x:Bind} dan {Binding} sebagian besar setara secara fungsional. Tetapi {x:Bind} memiliki informasi jenis untuk sumber pengikatan, dan menghasilkan kode sumber pada waktu kompilasi. Dengan {x:Bind}, Anda mendapatkan jenis deteksi masalah yang sama yang Anda dapatkan dengan sisa kode Anda. Deteksi tersebut mencakup validasi saat kompilasi dari ekspresi pengikatan Anda dan penelusuran kesalahan dengan menetapkan titik henti dalam kode sumber yang dihasilkan sebagai kelas parsial untuk halaman Anda. Anda dapat menemukan kelas ini di file di folder Anda obj , dengan nama seperti (untuk C#) <view name>.g.cs). Jika Anda mengalami masalah dengan pengikatan, aktifkan Hentian Saat Pengecualian Tidak Tertangani di debugger Microsoft Visual Studio. Debugger memutuskan eksekusi pada saat itu, dan Anda kemudian dapat men-debug apa yang salah. Kode yang dihasilkan oleh {x:Bind} mengikuti pola yang sama untuk setiap bagian dari grafik simpul sumber pengikatan, dan Anda dapat menggunakan info di jendela Call Stack untuk membantu menentukan urutan panggilan yang menyebabkan masalah.

{Binding} tidak memiliki informasi tipe untuk sumber pengikatan. Tetapi saat Anda menjalankan aplikasi dengan debugger terlampir, kesalahan pengikatan apa pun muncul di jendela Kegagalan Pengikatan Output dan XAML di Visual Studio. Untuk informasi selengkapnya tentang kesalahan pengikatan debug di Visual Studio, lihat diagnostik pengikatan data XAML.

Membuat pengikatan dalam kode

Nota

Bagian ini hanya berlaku untuk {Binding}, karena Anda tidak dapat membuat pengikatan {x:Bind} dalam kode. Namun, Anda dapat mencapai beberapa manfaat yang sama dengan {x:Bind}DependencyObject.RegisterPropertyChangedCallback, yang memungkinkan Anda mendaftar untuk pemberitahuan perubahan pada properti dependensi apa pun.

Anda juga dapat menyambungkan elemen UI ke data dengan menggunakan kode prosedural alih-alih XAML. Untuk melakukan ini, buat objek Pengikatan baru, atur properti yang sesuai, lalu panggil FrameworkElement.SetBinding atau BindingOperations.SetBinding. Membuat pengikatan secara terprogram berguna saat Anda ingin memilih nilai properti pengikatan pada waktu proses atau berbagi satu pengikatan di antara beberapa kontrol. Namun, Anda tidak dapat mengubah nilai properti pengikatan setelah memanggil SetBinding.

Contoh berikut menunjukkan cara menerapkan pengikatan dalam kode.

<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
var textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;

// Create the binding and associate it with the text box.
var binding = new Binding { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);

Perbandingan fitur {x:Bind} dan {Binding}

Fitur {x:Bind} vs. {Binding} Catatan
Jalur adalah properti default {x:Bind a.b.c}
-
{Binding a.b.c}
Properti jalur {x:Bind Path=a.b.c}
-
{Binding Path=a.b.c}
Di x:Bind, Path berakar pada Jendela secara default, bukan DataContext.
Indexer {x:Bind Groups[2].Title}
-
{Binding Groups[2].Title}
Mengikat ke item yang ditentukan dalam koleksi. Hanya indeks berbasis bilangan bulat yang didukung.
Properti terlampir {x:Bind Button22.(Grid.Row)}
-
{Binding Button22.(Grid.Row)}
Properti terlampir ditentukan menggunakan tanda kurung. Jika properti tidak dideklarasikan dalam namespace XAML, awali dengan namespace XML, yang harus dipetakan ke namespace kode di kepala dokumen.
Casting {x:Bind groups[0].(data:SampleDataGroup.Title)}
-
Tidak diperlukan untuk {Binding}.
Cast ditentukan menggunakan tanda kurung. Jika properti tidak dideklarasikan dalam namespace XAML, awali dengan namespace XML, yang harus dipetakan ke namespace kode di kepala dokumen.
Converter {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}}
Deklarasikan pengonversi di akar Jendela, Kontrol, ResourceDictionary, atau di App.xaml.
ConverterParameter, ConverterLanguage {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
Deklarasikan pengonversi di akar Jendela, Kontrol, ResourceDictionary, atau di App.xaml.
TargetNullValue {x:Bind Name, TargetNullValue=0}
-
{Binding Name, TargetNullValue=0}
Digunakan saat daun ekspresi pengikatan null. Gunakan tanda kutip tunggal untuk nilai string.
FallbackValue {x:Bind Name, FallbackValue='empty'}
-
{Binding Name, FallbackValue='empty'}
Digunakan ketika bagian mana pun dari jalur untuk pengikatan (kecuali untuk daun) null.
ElementName {x:Bind slider1.Value}
-
{Binding Value, ElementName=slider1}
Dengan {x:Bind} Anda mengikat ke bidang; Path berakar di Jendela secara default, sehingga Anda dapat mengakses elemen bernama apa pun melalui bidangnya.
RelativeSource: Diri sendiri <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />
-
<Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... />
Dengan {x:Bind}, beri nama elemen dan gunakan namanya di Path.
RelativeSource: TemplatedParent Tidak diperlukan untuk {x:Bind}
-
{Binding <path>, RelativeSource={RelativeSource TemplatedParent}}
Dengan {x:Bind}, TargetType on ControlTemplate menunjukkan pengikatan ke induk templat. Untuk {Binding}, pengikatan templat reguler dapat digunakan dalam templat kontrol untuk sebagian besar penggunaan. Tetapi gunakan TemplatedParent di mana Anda perlu menggunakan pengonversi, atau pengikatan dua arah.
Sumber Tidak diperlukan untuk {x:Bind}
-
<ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/>
Untuk {x:Bind} Anda dapat langsung menggunakan elemen bernama, menggunakan properti, atau jalur statis.
Pengaturan {x:Bind Name, Mode=OneWay}
-
{Binding Name, Mode=TwoWay}
Modebisa , OneTimeOneWay, atau TwoWay. {x:Bind} default ke OneTime; {Binding} default ke OneWay.
UpdateSourceTrigger {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
-
{Binding UpdateSourceTrigger=PropertyChanged}
UpdateSourceTriggerbisa , DefaultLostFocus, atau PropertyChanged. {x:Bind} tidak mendukung UpdateSourceTrigger=Explicit. {x:Bind} PropertyChanged menggunakan perilaku untuk semua kasus kecuali TextBox.Text, di mana ia menggunakan LostFocus perilaku.

Lihat juga