Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Pengikatan data di aplikasi WinUI memungkinkan Anda menghubungkan kontrol secara efisien ke sumber data. Pelajari cara mengikat kontrol ke satu item atau kumpulan item, mengontrol perenderan item, menerapkan tampilan detail, dan memformat data untuk ditampilkan. Untuk detail selengkapnya, lihat Pengikatan data secara mendalam.
Prasyarat
Topik ini mengasumsikan bahwa Anda tahu cara membuat aplikasi WinUI dasar dengan Windows App SDK. Untuk petunjuk tentang membuat aplikasi WinUI pertama Anda, lihat Membuat aplikasi WinUI.
Membuat proyek
Buat Aplikasi Kosong WinUI baru, proyek C# Paket. Beri nama "Mulai Cepat".
Ikat ke satu item
Setiap pengikatan terdiri dari target pengikatan dan sumber pengikatan. Biasanya, target adalah properti kontrol atau elemen UI lainnya, dan sumbernya adalah properti instans kelas (model data, atau model tampilan). Contoh ini memperlihatkan cara mengikat kontrol ke satu item. Targetnya adalah properti Text dari TextBlock. Sumbernya adalah instans kelas sederhana bernama Recording yang mewakili rekaman audio. Mari kita lihat kelas terlebih dahulu.
Tambahkan kelas baru ke proyek Anda, dan beri nama kelas Recording.
namespace Quickstart
{
public class Recording
{
public string ArtistName { get; set; }
public string CompositionName { get; set; }
public DateTime ReleaseDateTime { get; set; }
public Recording()
{
ArtistName = "Wolfgang Amadeus Mozart";
CompositionName = "Andante in C for Piano";
ReleaseDateTime = new DateTime(1761, 1, 1);
}
public string OneLineSummary
{
get
{
return $"{CompositionName} by {ArtistName}, released: "
+ ReleaseDateTime.ToString("d");
}
}
}
public class RecordingViewModel
{
private Recording defaultRecording = new();
public Recording DefaultRecording { get { return defaultRecording; } }
}
}
Selanjutnya, ekspos kelas sumber pengikatan dari kelas yang mewakili jendela markup Anda. Tambahkan properti jenis RecordingViewModel ke MainWindow.xaml.cs.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public RecordingViewModel ViewModel{ get; } = new RecordingViewModel();
}
}
Bagian terakhir adalah mengikat TextBlock ke properti ViewModel.DefaultRecording.OneLineSummary.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Berikut hasilnya.
Ikat ke kumpulan item
Skenario umum adalah mengikat kumpulan objek bisnis. Di C#, gunakan kelas T ObservableCollection<> generik untuk pengikatan data. Ini mengimplementasikan antarmuka INotifyCollectionChanged , yang menyediakan pemberitahuan perubahan pada pengikatan saat item ditambahkan atau dihapus. Namun, karena bug yang diketahui dalam mode rilis WinUI pada .NET 8 dan versi lebih baru, Anda mungkin perlu menggunakan List<T> dalam beberapa skenario, terutama jika koleksi Anda statis dan tidak berubah setelah inisialisasi. Jika UI Anda perlu memperbarui saat pengumpulan berubah pada runtime, gunakan ObservableCollection<T>. Jika Anda hanya perlu menampilkan sekumpulan item tetap, List<T> sudah cukup. Selain itu, jika Anda ingin kontrol terikat Anda diperbarui dengan perubahan pada properti objek dalam koleksi, objek tersebut harus mengimplementasikan INotifyPropertyChanged. Untuk informasi selengkapnya, lihat pengikatan data secara mendalam.
Nota
Dengan menggunakan List<T>, Anda mungkin tidak menerima pemberitahuan perubahan untuk perubahan koleksi. Jika Anda perlu menanggapi perubahan, pertimbangkan untuk menggunakan ObservableCollection<T>. Dalam contoh ini, Anda tidak perlu menanggapi perubahan koleksi, jadi List<T> sudah cukup.
Contoh berikut mengikat ListView ke kumpulan Recording objek. Pertama, tambahkan koleksi ke model tampilan Anda. Tambahkan anggota baru ini ke RecordingViewModel kelas .
public class RecordingViewModel
{
...
private List<Recording> recordings = new();
public List<Recording> Recordings{ get{ return recordings; } }
public RecordingViewModel()
{
recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
}
}
Kemudian ikat ListView ke ViewModel.Recordings properti .
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Anda belum menyediakan templat data untuk kelas tersebut Recording , jadi yang terbaik yang dapat dilakukan kerangka kerja UI adalah memanggil ToString untuk setiap item di ListView. Implementasi bawaan ToString mengembalikan nama jenis.
Untuk memperbaiki masalah ini, Anda dapat mengganti ToString untuk mengembalikan nilai OneLineSummary, atau Anda dapat menyediakan template data. Opsi templat data adalah solusi yang lebih umum dan fleksibel. Anda menentukan templat data dengan menggunakan properti ContentTemplate kontrol konten atau properti ItemTemplate kontrol item. Berikut adalah dua cara Anda dapat merancang templat data untuk Recording bersama dengan ilustrasi hasilnya.
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<TextBlock Text="{x:Bind OneLineSummary}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Untuk informasi selengkapnya tentang sintaks XAML, lihat Membuat UI dengan XAML. Untuk informasi selengkapnya tentang tata letak kontrol, lihat Menentukan tata letak dengan XAML.
Menambahkan tampilan detail
Anda dapat memilih untuk menampilkan semua detail objek Recording di ListView item. Tapi pendekatan itu membutuhkan banyak ruang. Sebagai gantinya, Anda dapat menampilkan cukup data dalam item untuk mengidentifikasinya. Saat pengguna membuat pilihan, Anda dapat menampilkan semua detail item yang dipilih di bagian terpisah dari UI yang dikenal sebagai tampilan detail. Pengaturan ini juga dikenal sebagai tampilan utama/detail atau tampilan daftar/detail.
Anda dapat menerapkan pengaturan ini dengan dua cara. Anda dapat menghubungkan tampilan detail ke properti SelectedItem dari ListView . Atau Anda dapat menggunakan CollectionViewSource. Dalam kasus ini, Anda mengikat kedua ListView dan tampilan detail ke CollectionViewSource. Pendekatan ini menangani item yang saat ini dipilih untuk Anda. Kedua teknik ditampilkan di bagian berikut, dan keduanya memberikan hasil yang sama (ditunjukkan dalam ilustrasi).
Nota
Sejauh ini dalam topik ini, Anda hanya menggunakan ekstensi markup {x:Bind}. Tetapi kedua teknik yang ditunjukkan di bagian berikut memerlukan ekstensi markup {Binding} yang lebih fleksibel (tetapi kurang berkinerja).
Pertama, berikut adalah teknik SelectedItem. Untuk aplikasi C#, satu-satunya perubahan yang diperlukan adalah markup.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
Margin="0,24,0,0">
<TextBlock Text="{Binding ArtistName}"/>
<TextBlock Text="{Binding CompositionName}"/>
<TextBlock Text="{Binding ReleaseDateTime}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
Untuk teknik CollectionViewSource, pertama-tama tambahkan CollectionViewSource sebagai sumber daya di tingkat atas Grid.
<Grid.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>
Nota
Kelas Jendela di WinUI tidak memiliki properti Resources. Anda dapat menambahkan CollectionViewSource ke elemen Grid tingkat atas (atau elemen UI induk lainnya seperti StackPanel) sebagai gantinya. Jika Anda bekerja dalam Page, Anda dapat menambahkan CollectionViewSource ke Page.Resources.
Kemudian, sesuaikan pengikatan pada ListView (yang tidak lagi perlu diberi nama) dan pada tampilan detail untuk menggunakan CollectionViewSource. Dengan mengikat tampilan detail langsung ke CollectionViewSource, Anda menyiratkan bahwa Anda ingin mengikat item saat ini dalam pengikatan di mana jalur tidak dapat ditemukan pada koleksi itu sendiri. Tidak perlu menentukan properti CurrentItem sebagai jalur untuk pengikatan, meskipun Anda dapat melakukannya jika ada ambiguitas.
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
Dan inilah hasil yang identik dalam setiap kasus.
Memformat atau mengonversi nilai data untuk ditampilkan
Penyajian di atas memiliki masalah. Properti ReleaseDateTime ini bukan hanya tanggal; ini adalah DateTime. Jadi, ini ditampilkan dengan akurasi tinggi yang melebihi kebutuhan Anda. Salah satu solusinya adalah menambahkan properti string ke kelas Recording yang mengembalikan setara dengan ReleaseDateTime.ToString("d"). Penamaan properti tersebut menunjukkan bahwa properti ReleaseDate mengembalikan tanggal, dan bukan tanggal dan waktu. Menamainya ReleaseDateAsString menunjukkan bahwa fungsi ini mengembalikan string.
Solusi yang lebih fleksibel adalah menggunakan pengonversi nilai. Berikut adalah contoh cara menulis pengonversi nilai Anda sendiri. Tambahkan kode berikut ke file kode sumber Recording.cs Anda.
public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
// This converts the value object to the string to display.
// This will work with most simple types.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// Retrieve the format string and use it to format the value.
string formatString = parameter as string;
if (!string.IsNullOrEmpty(formatString))
{
return string.Format(formatString, value);
}
// If the format string is null or empty, simply
// call ToString() on the value.
return value.ToString();
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Sekarang Anda dapat menambahkan sebuah instans StringFormatter sebagai sumber daya dan menggunakannya pada pengikatan TextBlock yang menampilkan properti ReleaseDateTime.
<Grid.Resources>
...
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Seperti yang Anda lihat, untuk fleksibilitas dalam pemformatan, markup meneruskan string format ke pengonversi melalui parameter konverter. Dalam contoh kode yang ditunjukkan dalam topik ini, pengonversi nilai C# menggunakan parameter tersebut.
Berikut hasilnya.
Perbedaan antara Pengikatan Data dan x:Bind
Saat bekerja dengan pengikatan data di aplikasi WinUI, Anda mungkin menemukan dua mekanisme pengikatan utama: Binding dan x:Bind. Meskipun keduanya melayani tujuan menghubungkan elemen UI ke sumber data, keduanya memiliki perbedaan yang berbeda:
-
x:Bind: Menawarkan pemeriksaan pada waktu kompilasi, performa yang lebih baik, dan bertipedata kuat. Ini ideal untuk skenario di mana Anda mengetahui struktur data pada waktu kompilasi. -
Binding: Menyediakan evaluasi runtime dan lebih fleksibel untuk skenario dinamis, seperti ketika struktur data tidak diketahui pada waktu kompilasi.
Skenario tidak didukung oleh x:Bind
Meskipun x:Bind kuat, Anda tidak dapat menggunakannya dalam skenario tertentu:
-
Struktur data dinamis: Jika struktur data tidak diketahui pada waktu kompilasi, Anda tidak dapat menggunakan
x:Bind. -
Pengikatan elemen ke elemen:
x:Bindtidak mendukung pengikatan langsung antara dua elemen UI. -
Pengikatan ke
DataContext:x:Bindtidak secara otomatis mewarisiDataContextelemen induk. -
Pengikatan dua arah dengan
Mode=TwoWay: Meskipun didukung,x:Bindmemerlukan implementasiINotifyPropertyChangedeksplisit untuk properti apa pun yang Anda inginkan untuk diperbarui UI saat sumber berubah, baik menggunakan pengikatan satu arah atau dua arah. Perbedaan utama dengan pengikatan dua arah adalah perubahan juga mengalir dari UI kembali ke sumbernya.
Untuk contoh praktis dan pemahaman yang lebih mendalam tentang kapan harus menggunakan masing-masing, lihat topik berikut:
Konten terkait
Windows developer