Pengikatan data secara mendalam

API penting

Catatan

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

Topik ini adalah tentang pengikatan data untuk API yang berada di namespace Windows.UI.Xaml.Data.

Pengikatan data adalah cara bagi UI aplikasi Anda untuk menampilkan data, dan secara opsional agar tetap sinkron dengan data tersebut. Pengikatan data memungkinkan Anda memisahkan kekhawatiran data dari kekhawatiran UI, dan yang menghasilkan model konseptual yang lebih sederhana serta keterbacaan, keterujian, dan keberlanjutan aplikasi Anda yang lebih baik.

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. Ini adalah mode pengikatan yang 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 contoh.

  • 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 keduanya biasanya dideklarasikan dalam markup UI. Anda dapat memilih untuk menggunakan ekstensi markup {x:Bind} atau ekstensi markup {Binding}. Dan Anda bahkan dapat menggunakan campuran keduanya di aplikasi yang sama—bahkan pada elemen UI yang sama. {x:Bind} baru 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.

Contoh aplikasi yang menunjukkan {x:Bind}

Aplikasi sampel yang menunjukkan {Binding}

Setiap pengikatan melibatkan potongan-potongan ini

  • Sumber pengikatan. Ini adalah sumber data untuk pengikatan, dan dapat menjadi instans kelas apa pun yang memiliki anggota yang nilainya ingin Anda tampilkan di UI Anda.
  • Target pengikatan. Ini adalah DependencyProperty dari FrameworkElement di UI Anda yang menampilkan data.
  • Objek pengikatan. Ini adalah bagian yang 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, kita akan melihat lebih dekat sumber pengikatan, target pengikatan, dan objek pengikatan. Dan kita akan menautkan bagian bersama dengan contoh pengikatan konten tombol ke properti string bernama NextButtonText, yang termasuk dalam kelas bernama HostViewModel.

Sumber pengikatan

Berikut adalah implementasi kelas yang sangat rudimenter yang dapat kita gunakan sebagai sumber pengikatan.

Jika Anda menggunakan C++/WinRT, tambahkan item Midl File (.idl) baru ke proyek, bernama seperti yang ditunjukkan dalam contoh kode C++/WinRT yang tercantum di bawah ini. Ganti konten file baru tersebut dengan kode MIDL 3.0 yang ditampilkan dalam daftar, buat proyek untuk dihasilkan HostViewModel.h dan .cpp, lalu tambahkan kode ke file yang dihasilkan agar sesuai dengan daftar. Untuk informasi selengkapnya tentang file yang dihasilkan dan cara menyalinnya ke proyek Anda, lihat kontrol XAML; mengikat properti C++/WinRT.

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

    public string NextButtonText { get; set; }
}
// HostViewModel.idl
namespace DataBindingInDepth
{
    runtimeclass HostViewModel
    {
        HostViewModel();
        String NextButtonText;
    }
}

// HostViewModel.h
// Implement the constructor like this, and add this field:
...
HostViewModel() : m_nextButtonText{ L"Next" } {}
...
private:
    std::wstring m_nextButtonText;
...

// HostViewModel.cpp
// Implement like this:
...
hstring HostViewModel::NextButtonText()
{
    return hstring{ m_nextButtonText };
}

void HostViewModel::NextButtonText(hstring const& value)
{
    m_nextButtonText = value;
}
...

Implementasi HostViewModel, dan propertinya NextButtonText, hanya sesuai untuk pengikatan satu kali. Tetapi pengikatan satu arah dan dua arah sangat umum, dan dalam jenis pengikatan UI tersebut secara otomatis diperbarui sebagai respons terhadap perubahan nilai data sumber pengikatan. Agar jenis pengikatan tersebut berfungsi dengan benar, Anda perlu membuat sumber pengikatan Anda "dapat diamati" ke objek pengikatan. Jadi dalam contoh kami, jika kita ingin mengikat satu arah atau dua arah ke properti NextButtonText , maka setiap perubahan yang terjadi pada run-time ke nilai properti tersebut perlu dibuat dapat diamati ke objek pengikatan.

Salah satu cara melakukannya adalah dengan memperoleh kelas yang mewakili sumber pengikatan Anda dari DependencyObject, dan mengekspos nilai data melalui DependencyProperty. Itulah bagaimana FrameworkElement menjadi dapat diamati. FrameworkElements 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. Ini benar-benar hanya melibatkan penerapan satu acara bernama PropertyChanged. Contoh menggunakan HostViewModel ada di bawah ini.

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

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

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

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

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
// HostViewModel.idl
namespace DataBindingInDepth
{
    runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        HostViewModel();
        String NextButtonText;
    }
}

// HostViewModel.h
// Add this field:
...
    winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
    void PropertyChanged(winrt::event_token const& token) noexcept;

private:
    winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
...

// HostViewModel.cpp
// Implement like this:
...
void HostViewModel::NextButtonText(hstring const& value)
{
    if (m_nextButtonText != value)
    {
        m_nextButtonText = value;
        m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"NextButtonText" });
    }
}

winrt::event_token HostViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
    return m_propertyChanged.add(handler);
}

void HostViewModel::PropertyChanged(winrt::event_token const& token) noexcept
{
    m_propertyChanged.remove(token);
}
...

Sekarang properti NextButtonText 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 PropertyChanged . Ketika peristiwa tersebut dinaikkan, handler objek pengikatan menerima argumen yang berisi nama properti yang telah berubah. Begitulah objek pengikatan mengetahui nilai properti mana yang akan digunakan dan dibaca lagi.

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

public class HostViewModel : BindableBase
{
    private string nextButtonText;

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

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set { this.SetProperty(ref this.nextButtonText, value); }
    }
}
// Your BindableBase base class should itself derive from Windows::UI::Xaml::DependencyObject. Then, in HostViewModel.idl, derive from BindableBase instead of implementing INotifyPropertyChanged.

Catatan

Untuk C++/WinRT, kelas runtime apa pun yang Anda deklarasikan dalam aplikasi Anda yang berasal dari kelas dasar dikenal sebagai kelas yang dapat disusun. Dan ada kendala di sekitar kelas yang dapat dikomposisikan. Agar aplikasi lulus tes Windows App Certification Kit yang digunakan oleh Visual Studio dan oleh Microsoft Store untuk memvalidasi pengiriman (dan oleh karena itu agar aplikasi berhasil diserap ke Microsoft Store), kelas yang dapat disusun pada akhirnya harus berasal dari kelas dasar Windows. Artinya kelas di akar hierarki warisan harus merupakan jenis yang berasal dari namespace Windows.*. Jika Anda perlu memperoleh kelas runtime dari kelas dasar—misalnya, untuk menerapkan kelas BindableBase untuk semua model tampilan Anda untuk diperoleh—maka Anda dapat memperoleh dari Windows.UI.Xaml.DependencyObject.

Menaikkan peristiwa PropertyChanged 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.

Sumber pengikatan dapat diperlakukan baik sebagai objek tunggal yang propertinya berisi data, atau sebagai kumpulan objek. Dalam kode C# dan Visual Basic, Anda dapat mengikat satu kali ke objek yang mengimplementasikan Daftar (Dari T) untuk menampilkan koleksi yang tidak berubah pada run-time. Untuk koleksi yang dapat diamati (mengamati kapan item ditambahkan ke dan dihapus dari koleksi), ikatan satu arah ke ObservableCollection(Of T) sebagai gantinya. Dalam kode C++/CX, Anda dapat mengikat Vektor< T> untuk koleksi yang dapat diamati dan tidak dapat diamati, dan C++/WinRT memiliki jenisnya sendiri. Untuk mengikat kelas koleksi Anda sendiri, gunakan panduan dalam tabel berikut.

Skenario C# dan VB (CLR) C++/WinRT C++/CX
Ikat ke objek. Bisa menjadi objek apa pun. Bisa menjadi objek apa pun. Objek harus memiliki BindableAttribute atau mengimplementasikan ICustomPropertyProvider.
Mendapatkan pemberitahuan perubahan properti dari objek terikat. Objek harus mengimplementasikan INotifyPropertyChanged. Objek harus mengimplementasikan INotifyPropertyChanged. Objek harus mengimplementasikan INotifyPropertyChanged.
Ikat ke koleksi. Daftar(dari T) IVector dari IInspectable, atau IBindableObservableVector. Lihat kontrol item XAML; ikat ke koleksi dan Koleksi C++/WinRT dengan C++/WinRT. Vektor<T>
Dapatkan pemberitahuan perubahan koleksi dari koleksi terikat. ObservableCollection(Dari T) IObservableVector dari IInspectable. Misalnya, winrt::single_threaded_observable_vector<T>. IObservableVector<T>. Vektor<T> mengimplementasikan antarmuka ini.
Terapkan koleksi yang mendukung pengikatan. Perluas Daftar(Dari T) atau terapkan IList, IList(Of Object), IEnumerable, atau IEnumerable(Of Object). Pengikatan ke IList generik (Dari T) dan IEnumerable(Of T) tidak didukung. Terapkan IVector dari IInspectable. Lihat kontrol item XAML; ikat ke koleksi dan Koleksi C++/WinRT dengan C++/WinRT. Terapkan IBindableVector, IBindableIterable, IVector<Object^>, IIterable<Object^>, IVector<IInspectable*>, atau IInspectable IIterable<*.> Pengikatan ke IVector<T> generik dan IIterable<T> tidak didukung.
Terapkan koleksi yang mendukung pemberitahuan perubahan koleksi. Perluas ObservableCollection(Of T) atau terapkan (non-generik) IList dan INotifyCollectionChanged. Terapkan IObservableVector dari IInspectable, atau IBindableObservableVector. Terapkan IBindableVector dan IBindableObservableVector.
Terapkan koleksi yang mendukung pemuatan bertahap. Perluas ObservableCollection(Of T) atau terapkan (non-generik) IList dan INotifyCollectionChanged. Selain itu, terapkan ISupportIncrementalLoading. Terapkan IObservableVector dari IInspectable, atau IBindableObservableVector. Selain itu, terapkan ISupportIncrementalLoading Terapkan IBindableVector, IBindableObservableVector, dan 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 di bawah ini, properti Button.Content adalah target pengikatan, dan nilainya diatur ke ekstensi markup yang mendeklarasikan objek pengikatan. {x:Bind} pertama ditampilkan, lalu {Binding}. Mendeklarasikan pengikatan dalam markup adalah kasus umum (nyaman, dapat dibaca, dan dapat diperkakas). Tetapi Anda dapat menghindari markup dan secara imperatif (terprogram) membuat instans kelas Pengikatan sebagai gantinya jika Perlu.

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

Jika Anda menggunakan ekstensi komponen C++/WinRT atau Visual C++ (C++/CX), maka Anda harus menambahkan atribut BindableAttribute ke kelas runtime apa pun yang ingin Anda gunakan ekstensi markup {Binding}.

Penting

Jika Anda menggunakan C++/WinRT, atribut BindableAttribute tersedia jika Anda telah menginstal Windows SDK versi 10.0.17763.0 (Windows 10, versi 1809), atau yang lebih baru. Tanpa atribut tersebut , Anda harus mengimplementasikan antarmuka ICustomPropertyProvider dan ICustomProperty agar dapat menggunakan ekstensi markup {Binding} .

Objek pengikatan dideklarasikan menggunakan {x:Bind}

Ada satu langkah yang perlu kita lakukan sebelum kita menulis markup {x:Bind} kita. Kita perlu mengekspos kelas sumber pengikatan dari kelas yang mewakili halaman markup kita. Kami melakukannya dengan menambahkan properti (jenis HostViewModel dalam hal ini) ke kelas halaman MainPage kami.

namespace DataBindingInDepth
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.ViewModel = new HostViewModel();
        }
    
        public HostViewModel ViewModel { get; set; }
    }
}
// MainPage.idl
import "HostViewModel.idl";

namespace DataBindingInDepth
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        HostViewModel ViewModel{ get; };
    }
}

// MainPage.h
// Include a header, and add this field:
...
#include "HostViewModel.h"
...
    DataBindingInDepth::HostViewModel ViewModel();

private:
    DataBindingInDepth::HostViewModel m_viewModel{ nullptr };
...

// MainPage.cpp
// Implement like this:
...
MainPage::MainPage()
{
    InitializeComponent();

}

DataBindingInDepth::HostViewModel MainPage::ViewModel()
{
    return m_viewModel;
}
...

Setelah itu, kita sekarang dapat melihat lebih dekat markup yang mendeklarasikan objek pengikatan. Contoh di bawah ini menggunakan target pengikatan Button.Content yang sama dengan yang kami gunakan di bagian "Target pengikatan" sebelumnya, dan menunjukkannya terikat ke properti HostViewModel.NextButtonText.

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

Perhatikan nilai yang kami tentukan untuk Jalur. Nilai ini ditafsirkan dalam konteks halaman itu sendiri, dan dalam hal ini jalur dimulai dengan merujuk properti ViewModel yang baru saja kita tambahkan ke halaman MainPage . Properti tersebut mengembalikan instans HostViewModel , sehingga kita dapat melakukan titik ke objek tersebut untuk mengakses properti HostViewModel.NextButtonText . Dan kami menentukan Mode, untuk mengambil alih default {x:Bind} satu kali.

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 menggambarkan bahwa properti HostViewModel.NextButtonText memang dapat diamati, tambahkan penanganan aktivitas Klik ke tombol, dan perbarui nilai HostViewModel.NextButtonText. Buat, jalankan, dan klik tombol untuk melihat nilai pembaruan Konten tombol.

// MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.ViewModel.NextButtonText = "Updated Next button text";
}
// MainPage.cpp
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ViewModel().NextButtonText(L"Updated Next button text");
}

Catatan

Perubahan pada TextBox.Text dikirim ke sumber terikat dua arah saat TextBox kehilangan fokus, dan tidak setelah setiap penekanan tombol pengguna.

DataTemplate dan x:DataType

Di dalam DataTemplate (apakah digunakan sebagai templat item, templat konten, atau templat header), nilai Jalur tidak ditafsirkan dalam konteks halaman, tetapi dalam konteks objek data yang di-template. Saat menggunakan {x:Bind} dalam templat data, sehingga pengikatannya dapat divalidasi (dan kode efisien yang dihasilkan untuk mereka) pada waktu kompilasi, DataTemplate perlu mendeklarasikan jenis objek datanya menggunakan x:DataType. Contoh yang diberikan di bawah ini dapat digunakan sebagai ItemTemplate kontrol item yang terikat ke kumpulan objek SampleDataGroup .

<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

Pertimbangkan misalnya bahwa Anda memiliki jenis bernama SampleDataGroup, yang mengimplementasikan properti string bernama Judul. Dan Anda memiliki properti MainPage.SampleDataGroupAsObject, yang berjenis objek, tetapi yang benar-benar mengembalikan instans SampleDataGroup. Pengikatan <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> akan mengakibatkan kesalahan kompilasi karena properti Judul tidak ditemukan pada objek jenis. Obat untuk ini adalah menambahkan cast ke sintaks Jalur Anda seperti ini: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Berikut adalah contoh lain di mana Element dinyatakan sebagai objek tetapi sebenarnya adalah TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>. Dan cast memperbaiki masalah: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.

Jika data Anda dimuat secara asinkron

Kode untuk mendukung {x:Bind} dihasilkan pada waktu kompilasi di kelas parsial untuk halaman Anda. File-file ini dapat ditemukan di folder Anda obj , dengan nama seperti (untuk C#) <view name>.g.cs. Kode yang dihasilkan mencakup handler untuk peristiwa Pemuatan halaman Anda, dan handler tersebut memanggil metode Inisialisasi pada kelas yang dihasilkan yang mewakili pengikatan halaman Anda. Inisialisasipada gilirannya memanggil Pembaruan untuk mulai memindahkan data antara sumber pengikatan dan target. Pemuatan dinaikkan tepat sebelum lulus pengukuran pertama dari halaman atau kontrol pengguna. Jadi jika data Anda dimuat secara asinkron, data tersebut mungkin tidak siap pada saat Inisialisasi dipanggil. Jadi, 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 maka jauh lebih murah untuk menginisialisasinya dengan cara ini daripada memiliki pengikatan satu arah dan mendengarkan perubahan. Jika data Anda tidak mengalami perubahan mencolok, dan jika kemungkinan akan diperbarui sebagai bagian dari tindakan tertentu, maka Anda dapat membuat pengikatan satu kali, dan memaksa pembaruan manual kapan saja dengan panggilan ke Pembaruan.

Catatan

{x:Bind} tidak cocok untuk skenario yang terlambat terikat, seperti menavigasi struktur kamus objek JSON, atau mengetik bebek. "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 properti Usia akan sama-sama puas dengan objek Orang atau Anggur (dengan asumsi bahwa jenis tersebut masing-masing memiliki properti Usia). Untuk skenario ini, gunakan ekstensi markup {Binding} .

Objek pengikatan dideklarasikan menggunakan {Binding}

Jika Anda menggunakan ekstensi komponen C++/WinRT atau Visual C++ (C++/CX) maka, untuk menggunakan ekstensi markup {Binding} , Anda harus menambahkan atribut BindableAttribute ke kelas runtime apa pun yang ingin Anda ikat. Untuk menggunakan {x:Bind}, Anda tidak memerlukan atribut tersebut.

// HostViewModel.idl
// Add this attribute:
[Windows.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
...

Penting

Jika Anda menggunakan C++/WinRT, atribut BindableAttribute tersedia jika Anda telah menginstal Windows SDK versi 10.0.17763.0 (Windows 10, versi 1809), atau yang lebih baru. Tanpa atribut tersebut , Anda harus mengimplementasikan antarmuka ICustomPropertyProvider dan ICustomProperty agar dapat menggunakan ekstensi markup {Binding} .

{Pengikatan} mengasumsikan, secara default, bahwa Anda mengikat ke DataContext dari halaman markup Anda. Jadi, kami akan mengatur DataContext halaman kami menjadi contoh kelas sumber pengikatan kami (dari jenis HostViewModel dalam hal ini). Contoh di bawah ini menunjukkan markup yang mendeklarasikan objek pengikatan. Kami menggunakan target pengikatan Button.Content yang sama dengan yang kami gunakan di bagian "Target pengikatan" sebelumnya, dan kami mengikat ke properti HostViewModel.NextButtonText.

<Page xmlns:viewmodel="using:DataBindingInDepth" ... >
    <Page.DataContext>
        <viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
    </Page.DataContext>
    ...
    <Button Content="{Binding Path=NextButtonText}" ... />
</Page>
// MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.viewModelInDataContext.NextButtonText = "Updated Next button text";
}
// MainPage.cpp
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    viewModelInDataContext().NextButtonText(L"Updated Next button text");
}

Perhatikan nilai yang kami tentukan untuk Jalur. Nilai ini ditafsirkan dalam konteks DataContext halaman, yang dalam contoh ini diatur ke instans HostViewModel. Jalur mereferensikan properti HostViewModel.NextButtonText . Kita dapat menghilangkan Mode, karena default {Binding} dari satu arah berfungsi di sini.

Nilai default DataContext untuk elemen UI adalah nilai yang diwariskan dari induknya. Anda tentu saja dapat mengambil alih default tersebut dengan mengatur DataContext secara eksplisit , yang pada gilirannya diwariskan oleh turunan secara default. Mengatur DataContext secara eksplisit pada elemen berguna ketika Anda ingin memiliki beberapa pengikatan yang menggunakan sumber yang sama.

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

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

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

Catatan

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 harus mengonversi nilai dari satu jenis ke jenis lainnya. Akan 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 itu tidak fleksibel atau dapat diskalakan ketika Anda memiliki jumlah 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 string yang 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();
    }
}
// See the "Formatting or converting data values for display" section in the "Data binding overview" topic.

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 Konversi 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.

Catatan

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 properti FallbackValue 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 ToString apa pun yang menyembunyikan implementasi kelas dasar. Implementasi subkelas harus mengambil alih metode ToString kelas 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 ToString baru yang menyembunyikan implementasi kelas dasar.

Catatan

Mulai dari Windows 10, versi 1607, kerangka kerja XAML menyediakan boolean bawaan ke pengonversi Visibilitas. Pengonversi memetakan true ke nilai Enumerasi terlihat dan false ke Diciutkan sehingga Anda dapat mengikat properti Visibilitas ke boolean tanpa membuat pengonversi. Untuk menggunakan konverter bawaan, versi SDK target minimum aplikasi Anda harus 14393 atau yang lebih baru. Anda tidak dapat menggunakannya saat aplikasi menargetkan versi Windows 10 yang lebih lama. Untuk informasi selengkapnya tentang versi target, lihat Kode adaptif versi.

Pengikatan fungsi di {x:Bind}

{x:Bind} memungkinkan langkah terakhir di jalur pengikatan menjadi fungsi. Ini dapat digunakan untuk melakukan konversi, dan untuk melakukan pengikatan yang bergantung pada lebih dari satu properti. Lihat Fungsi dalam x:Bind

Pengikatan elemen-ke-elemen

Anda dapat mengikat properti dari satu elemen XAML ke properti elemen XAML lain. Berikut adalah contoh tampilannya dalam markup.

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

Penting

Untuk alur kerja yang diperlukan untuk pengikatan elemen-ke-elemen menggunakan C++/WinRT, lihat Pengikatan elemen-ke-elemen.

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). Anda menggunakan kembali kamus sumber daya dengan membuat instans 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 Anda ingin menggunakan {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 Windows.UI.Xaml.Data;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
    }
}

MainPage.xaml

<Page x:Class="ExampleNamespace.MainPage"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

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

Pengikatan peristiwa dan ICommand

{x:Bind} mendukung fitur yang disebut pengikatan peristiwa. Dengan fitur ini, Anda dapat menentukan handler untuk peristiwa menggunakan pengikatan, yang merupakan opsi tambahan selain menangani peristiwa dengan metode pada file code-behind. Katakanlah Anda memiliki properti RootFrame di kelas MainPage Anda.

public sealed partial class MainPage : Page
{
    ...
    public Frame RootFrame { get { return Window.Current.Content as Frame; } }
}

Anda kemudian dapat mengikat peristiwa Klik tombol ke metode pada objek Bingkai yang dikembalikan oleh properti RootFrame seperti ini. Perhatikan bahwa kami juga mengikat properti IsEnabled tombol ke anggota lain dari Bingkai yang sama.

<AppBarButton Icon="Forward" IsCompact="True"
IsEnabled="{x:Bind RootFrame.CanGoForward, Mode=OneWay}"
Click="{x:Bind RootFrame.GoForward}"/>

Metode yang kelebihan beban tidak dapat digunakan 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, Frame.GoForward tidak kelebihan beban dan tidak memiliki parameter (tetapi masih akan valid bahkan jika mengambil dua parameter objek ). Frame.GoBack kelebihan beban, jadi kita tidak dapat menggunakan metode itu dengan teknik ini.

Teknik pengikatan peristiwa mirip dengan menerapkan 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 kelas pembantu DelegateCommand yang akan Anda temukan di sampel QuizGame (di folder "Umum").

Mengikat ke kumpulan folder atau file

Anda dapat menggunakan API di namespace Windows.Storage untuk mengambil folder dan data file. Namun, berbagai metode GetFilesAsync, GetFoldersAsync, dan GetItemsAsync tidak mengembalikan nilai yang cocok untuk pengikatan ke kontrol daftar. Sebagai gantinya, Anda harus mengikat nilai pengembalian metode GetVirtualizedFilesVector, GetVirtualizedFoldersVector, dan GetVirtualizedItemsVector dari kelas FileInformationFactory. Contoh kode berikut dari sampel 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 akan 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, setiap perubahan tidak bertahan sampai Anda memanggil metode SavePropertiesAsync yang sesuai (misalnya, MusicProperties.SavePropertiesAsync). Anda harus menerapkan perubahan saat item kehilangan fokus karena 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 mengembalikan 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 kelas BookSku ) dan Anda mengelompokkan item dengan menggunakan properti umum sebagai kunci ( properti BookSku.AuthorName , 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
  • koleksi BookSkuyang properti AuthorName-nya 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 datar barang maka Anda tidak perlu melakukan sesuatu yang istimewa. 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. Nilai tambahan tambahan dari CollectionViewSource adalah bahwa ia melacak item saat ini, sehingga Anda dapat menjaga lebih dari satu kontrol item tetap sinkron dengan mengikat semuanya ke CollectionViewSource yang sama. 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, Daftar<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 jenis koleksi (seperti Daftar<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 di bawah ini menggambarkan pola "has-a-group". Kelas halaman memiliki properti bernama ViewModel, yang mengembalikan instans model tampilan kami. CollectionViewSource mengikat properti Penulis dari model tampilan (Penulis adalah kumpulan objek grup) dan juga menentukan bahwa itu adalah properti Author.BookSkus yang berisi item yang dikelompokkan. Terakhir, GridView terikat ke CollectionViewSource, dan memiliki gaya grup yang ditentukan sehingga dapat merender item dalam grup.

<Page.Resources>
    <CollectionViewSource
    x:Name="AuthorHasACollectionOfBookSku"
    Source="{x:Bind ViewModel.Authors}"
    IsSourceGrouped="true"
    ItemsPath="BookSkus"/>
</Page.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 Daftar<T> (di mana T adalah jenis item). Misalnya, 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 di bawah ini menggambarkan pola "is-a-group" menggunakan LINQ. Kali ini kami mengelompokkan buku berdasarkan genre, ditampilkan dengan nama genre di header grup. 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 (this.genres == null)
        {
            this.genres = from book in this.bookSkus
                          group book by book.genre into grp
                          orderby grp.Key
                          select grp;
        }
        return this.genres;
    }
}

Ingatlah bahwa saat menggunakan {x:Bind} dengan templat data, kita perlu menunjukkan jenis yang terikat dengan mengatur nilai x:DataType . Jika jenisnya generik, maka kita tidak dapat mengekspresikannya dalam markup sehingga kita 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 Bookstore2 menggambarkan 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 adalah kontrol ListView atau GridView yang terikat ke CollectionViewSource yang sama.

An illustration of a 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 instans CollectionViewSource bersama-sama dalam rantai. Ini disebut tampilan master/detail (atau daftar/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, saat mengganti nama properti, Anda juga perlu mengubah pengikatan apa pun yang mereferensikannya. Lupa melakukannya mengarah ke contoh umum bug pengikatan data, dan aplikasi Anda tidak akan mengompilasi atau tidak akan berjalan dengan benar.

Objek pengikatan yang dibuat oleh {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 dengan kode Anda lainnya. Itu termasuk validasi waktu kompilasi ekspresi pengikatan Anda, dan penelusuran kesalahan dengan mengatur titik henti dalam kode sumber yang dihasilkan sebagai kelas parsial untuk halaman Anda. Kelas-kelas ini dapat ditemukan di file di folder Anda obj , dengan nama seperti (untuk C#) <view name>.g.cs). Jika Anda memiliki masalah dengan pengikatan, aktifkan Hentian Aktifkan Pengecualian Tidak Tertangani di debugger Microsoft Visual Studio. Debugger akan memutuskan eksekusi pada saat itu, dan Anda kemudian dapat men-debug apa yang telah 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 Tumpukan Panggilan untuk membantu menentukan urutan panggilan yang menyebabkan masalah.

{Pengikatan} tidak memiliki informasi tipe untuk sumber pengikatan. Tetapi saat Anda menjalankan aplikasi dengan debugger terlampir, kesalahan pengikatan apa pun muncul di jendela Output di Visual Studio.

Membuat pengikatan dalam kode

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

Anda juga dapat menyambungkan elemen UI ke data 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 run-time atau berbagi pengikatan tunggal di antara beberapa kontrol. Namun, perhatikan bahwa Anda tidak dapat mengubah nilai properti pengikatan setelah Anda 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.
MyColors 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.
Binding binding = new Binding() { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);
' Create an instance of the MyColors class 
' that implements INotifyPropertyChanged. 
Dim textcolor As 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.
Dim binding As New Binding() With {.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, Jalur berakar di Halaman secara default, bukan DataContext.
Pengindeks {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, maka 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, maka 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}}
Pengonversi harus dideklarasikan di akar Halaman/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}
Pengonversi harus dideklarasikan di akar Halaman/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; Jalur berakar di Halaman secara default, sehingga elemen bernama apa pun dapat diakses melalui bidangnya.
RelativeSource: Self <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 Jalur.
RelativeSource: TemplatedParent Tidak diperlukan untuk {x:Bind}
-
{Binding <path>, RelativeSource={RelativeSource TemplatedParent}}
Dengan {x:Bind} TargetType di 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, gunakan properti atau jalur statis.
Mode {x:Bind Name, Mode=OneWay}
-
{Binding Name, Mode=TwoWay}
Mode dapat berupa OneTime, OneWay, atau TwoWay. {x:Bind} default ke OneTime; {Binding} default ke OneWay.
UpdateSourceTrigger {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
-
{Binding UpdateSourceTrigger=PropertyChanged}
UpdateSourceTrigger dapat berupa Default, LostFocus, atau PropertyChanged. {x:Bind} tidak mendukung UpdateSourceTrigger=Explicit. {x:Bind} menggunakan perilaku PropertyChanged untuk semua kasus kecuali TextBox.Text, di mana ia menggunakan perilaku LostFocus.