Pengikatan yang dikompilasi
Pengikatan data .NET Multi-platform App UI (.NET MAUI) memiliki dua masalah utama:
- Tidak ada validasi ekspresi pengikatan waktu kompilasi. Sebaliknya, pengikatan diselesaikan pada runtime. Oleh karena itu, pengikatan yang tidak valid tidak terdeteksi hingga runtime ketika aplikasi tidak berperilaku seperti yang diharapkan atau pesan kesalahan muncul.
- Biayanya tidak hemat biaya. Pengikatan diselesaikan pada runtime menggunakan inspeksi objek tujuan umum (refleksi), dan overhead melakukan ini bervariasi dari platform ke platform.
Pengikatan yang dikompilasi meningkatkan performa pengikatan data dalam aplikasi .NET MAUI dengan menyelesaikan ekspresi pengikatan pada waktu kompilasi daripada runtime. Selain itu, validasi ekspresi pengikatan waktu kompilasi ini memungkinkan pengalaman pemecahan masalah pengembang yang lebih baik karena pengikatan yang tidak valid dilaporkan sebagai kesalahan build.
Penting
Pengikatan yang dikompilasi diperlukan alih-alih pengikatan berbasis string di aplikasi NativeAOT, dan di aplikasi dengan pemangkasan penuh diaktifkan. Untuk informasi selengkapnya, lihat Memangkas aplikasi .NET MAUI dan penyebaran AOT Asli.
Pengikatan yang dikompilasi di XAML
Untuk menggunakan pengikatan yang dikompilasi di XAML, atur x:DataType
atribut pada VisualElement ke jenis objek yang akan diikat VisualElement dan anak-anaknya. Disarankan untuk mengatur x:DataType
atribut pada tingkat yang sama dalam hierarki tampilan saat BindingContext diatur. Namun, atribut ini dapat ditentukan ulang di lokasi mana pun dalam hierarki tampilan.
Penting
Pengikatan yang dikompilasi memerlukan penggunaan kompilasi XAML, yang diaktifkan secara default di .NET MAUI. Jika Anda telah menonaktifkan kompilasi XAML, Anda harus mengaktifkannya. Untuk informasi selengkapnya, lihat Kompilasi XAML.
Untuk menggunakan pengikatan yang dikompilasi di XAML, x:DataType
atribut harus diatur ke string literal, atau jenis menggunakan x:Type
ekstensi markup. Pada waktu kompilasi XAML, ekspresi pengikatan yang tidak valid akan dilaporkan sebagai kesalahan build. Namun, pengkompilasi XAML hanya akan melaporkan kesalahan build untuk ekspresi pengikatan pertama yang tidak valid yang ditemuinya. Setiap ekspresi pengikatan valid yang ditentukan pada VisualElement atau turunannya akan dikompilasi, terlepas dari apakah BindingContext diatur dalam XAML atau kode. Mengkompilasi ekspresi pengikatan menghasilkan kode yang dikompilasi yang akan mendapatkan nilai dari properti pada sumbernya, dan mengaturnya pada properti pada target yang ditentukan dalam markup. Selain itu, tergantung pada ekspresi pengikatan, kode yang dihasilkan dapat mengamati perubahan nilai properti sumber dan merefresh properti target , dan dapat mendorong perubahan dari target kembali ke sumber.
Penting
Pengikatan yang dikompilasi dinonaktifkan untuk ekspresi pengikatan XAML apa pun yang menentukan Source
properti . Ini karena Source
properti selalu diatur menggunakan x:Reference
ekstensi markup, yang tidak dapat diselesaikan pada waktu kompilasi.
Selain itu, pengikatan yang dikompilasi di XAML saat ini tidak didukung pada multi-pengikatan.
Secara default, .NET MAUI tidak menghasilkan peringatan build untuk pengikatan XAML yang tidak menggunakan pengikatan yang dikompilasi. Namun, Anda dapat memilih untuk mengikat peringatan yang dikompilasi yang diproduksi dengan mengatur $(MauiStrictXamlCompilation)
properti build ke true
dalam file proyek aplikasi Anda (*.csproj):
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Secara default, .NET MAUI menghasilkan peringatan build untuk pengikatan XAML yang tidak menggunakan pengikatan yang dikompilasi.
Untuk informasi selengkapnya tentang peringatan pengikatan yang dikompilasi XAML, lihat peringatan pengikatan yang dikompilasi XAML.
Menggunakan pengikatan yang dikompilasi di XAML
Contoh berikut menunjukkan menggunakan pengikatan yang dikompilasi antara tampilan .NET MAUI dan properti viewmodel:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
x:DataType="local:HslColorViewModel"
Title="Compiled Color Selector">
<ContentPage.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</ContentPage.BindingContext>
...
<StackLayout>
<BoxView Color="{Binding Color}"
... />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>
Membuat ContentPage instans HslColorViewModel
Color
dan menginisialisasi properti dalam tag elemen properti untuk BindingContext properti . juga ContentPage mendefinisikan x:DataType
atribut sebagai jenis viewmodel, menunjukkan bahwa ekspresi pengikatan apa pun dalam ContentPage hierarki tampilan akan dikompilasi. Ini dapat diverifikasi dengan mengubah ekspresi pengikatan apa pun untuk mengikat properti viewmodel yang tidak ada, yang akan mengakibatkan kesalahan build. Meskipun contoh ini mengatur x:DataType
atribut ke string literal, contoh ini juga dapat diatur ke jenis dengan x:Type
ekstensi markup. Untuk informasi selengkapnya tentang x:Type
ekstensi markup, lihat x:Type Markup Extension.
Penting
Atribut x:DataType
dapat ditentukan ulang kapan saja dalam hierarki tampilan.
Elemen BoxView, Label dan Slider tampilan mewarisi konteks pengikatan dari ContentPage. Tampilan ini adalah semua target pengikatan yang mereferensikan properti sumber di viewmodel. BoxView.Color
Untuk properti , dan Label.Text
properti , pengikatan data adalah OneWay
- properti dalam tampilan diatur dari properti di viewmodel. Namun, Slider.Value
properti menggunakan pengikatan TwoWay
. Ini memungkinkan masing-masing Slider diatur dari viewmodel, dan juga agar viewmodel diatur dari masing-masing Slider.
Ketika contoh pertama kali dijalankan, BoxViewelemen , Label dan Slider elemen semuanya diatur dari viewmodel berdasarkan properti awal Color
yang ditetapkan ketika viewmodel dibuat. Saat slider dimanipulasi, elemen dan Label diperbarui BoxView dengan sesuai:
Untuk informasi selengkapnya tentang pemilih warna ini, lihat ViewModels dan pemberitahuan perubahan properti.
Menggunakan pengikatan yang dikompilasi di XAML dalam DataTemplate
Pengikatan dalam ditafsirkan DataTemplate dalam konteks objek yang di-template. Oleh karena itu, saat menggunakan pengikatan yang dikompilasi dalam DataTemplate, DataTemplate kebutuhan untuk mendeklarasikan jenis objek datanya menggunakan x:DataType
atribut . Kegagalan untuk melakukan ini dapat mengakibatkan DataTemplate pewarisan yang salah x:DataType
dari cakupan induknya:
<ContentPage ...
x:DataType="local:AnimalsPageViewModel">
<!-- Binding to AnimalsPageViewModel.Animals -->
<CollectionView ItemsSource="{Binding Animals}">
<CollectionView.ItemTemplate>
<DataTemplate>
<!-- incorrect: compiler thinks you want to bind to AnimalsPageViewModel.Name -->
<Label Text="{Binding Name}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Contoh berikut menunjukkan pengaturan x:DataType
dengan benar pada DataTemplate:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorListPage"
Title="Compiled Color List">
<Grid>
...
<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
... >
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:NamedColor">
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
... />
<Label Text="{Binding FriendlyName}"
... />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- The BoxView doesn't use compiled bindings -->
<BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
... />
</Grid>
</ContentPage>
Properti ListView.ItemsSource
diatur ke properti statis NamedColor.All
. Kelas menggunakan NamedColor
refleksi .NET untuk menghitung semua bidang publik statis di Colors kelas, dan untuk menyimpannya dengan namanya dalam koleksi yang dapat diakses dari properti statis All
. Oleh karena itu, ListView diisi dengan semua NamedColor
instans. Untuk setiap item dalam ListViewkonteks pengikatan untuk item diatur ke NamedColor
objek. Elemen BoxView dan Label dalam ViewCell terikat ke NamedColor
properti.
DataTemplate mendefinisikan x:DataType
atribut menjadi NamedColor
jenis, menunjukkan bahwa ekspresi pengikatan apa pun dalam DataTemplate hierarki tampilan akan dikompilasi. Ini dapat diverifikasi dengan mengubah salah satu ekspresi pengikatan untuk mengikat ke properti yang tidak ada NamedColor
, yang akan mengakibatkan kesalahan build. Meskipun contoh ini mengatur x:DataType
atribut ke string literal, contoh ini juga dapat diatur ke jenis dengan x:Type
ekstensi markup. Untuk informasi selengkapnya tentang x:Type
ekstensi markup, lihat x:Type Markup Extension.
Ketika contoh pertama kali dijalankan, diisi ListView dengan NamedColor
instans. Saat item dalam ListView dipilih, BoxView.Color
properti diatur ke warna item yang dipilih di ListView:
Memilih item lain dalam ListView memperbarui warna BoxView.
Mengkompilasi pengikatan yang menentukan Source
properti
Sebelum .NET MAUI 9, kompilator XAML akan melewati kompilasi pengikatan yang menentukan Source
properti alih-alih BindingContext. Dari .NET MAUI 9, pengikatan ini dapat dikompilasi untuk memanfaatkan performa runtime yang lebih baik. Namun, pengoptimalan ini tidak diaktifkan secara default untuk menghindari melanggar kode aplikasi yang ada. Untuk mengaktifkan pengoptimalan ini, atur $(MauiEnableXamlCBindingWithSourceCompilation)
properti build ke true
dalam file proyek aplikasi Anda:
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
Kemudian, pastikan bahwa semua pengikatan Anda diannotasi dengan yang benar x:DataType
dan tidak mewarisi jenis data yang salah dari cakupan induknya:
<HorizontalStackLayout BindingContext="{x:Reference slider}" x:DataType="Slider">
<Label Text="{Binding Value}" />
<Label Text="{Binding Text, Source={x:Reference entry}, x:DataType=Entry}" />
</HorizontalStackLayout>
Catatan
Dalam kasus di mana ada pengikatan dengan Source
, tetapi mewarisi x:DataType
dari induk, mungkin ada ketidakcocokan antara x:DataType
dan jenis Source
. Dalam skenario ini, peringatan akan dihasilkan dan fallback ke pengikatan berbasis refleksi yang menyelesaikan jalur pengikatan pada runtime akan terjadi.
Menggabungkan pengikatan yang dikompilasi dengan pengikatan klasik di XAML
Ekspresi pengikatan hanya dikompilasi untuk hierarki tampilan tempat x:DataType
atribut ditentukan. Sebaliknya, setiap tampilan dalam hierarki di mana x:DataType
atribut tidak ditentukan akan menggunakan pengikatan klasik. Oleh karena itu dimungkinkan untuk menggabungkan pengikatan yang dikompilasi dan pengikatan klasik pada halaman. Misalnya, di bagian sebelumnya tampilan dalam DataTemplate penggunaan pengikatan yang dikompilasi, sementara BoxView yang diatur ke warna yang dipilih di ListView tidak.
Oleh karena itu, penataan x:DataType
atribut yang cermat dapat mengarah ke halaman menggunakan pengikatan kompilasi dan klasik. Atau, x:DataType
atribut dapat didefinisikan kembali pada titik mana pun dalam hierarki tampilan untuk null
menggunakan x:Null
ekstensi markup. Melakukan ini menunjukkan bahwa setiap ekspresi pengikatan dalam hierarki tampilan akan menggunakan pengikatan klasik. Contoh berikut menunjukkan pendekatan ini:
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<StackLayout x:DataType="{x:Null}"
Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
Akar StackLayout mengatur x:DataType
atribut menjadi HslColorViewModel
jenis, menunjukkan bahwa ekspresi pengikatan apa pun dalam hierarki tampilan akar StackLayout akan dikompilasi. Namun, bagian dalam StackLayout menentukan ulang x:DataType
atribut dengan null
x:Null
ekspresi markup. Oleh karena itu, ekspresi pengikatan dalam bagian dalam StackLayout menggunakan pengikatan klasik. BoxViewHanya , dalam hierarki tampilan akarStackLayout, menggunakan pengikatan yang dikompilasi.
Untuk informasi selengkapnya tentang x:Null
ekspresi markup, lihat x:Null Markup Extension.
Peringatan pengikatan yang dikompilasi XAML
Tabel berikut mencantumkan peringatan pengkompilasi untuk pengikatan yang dikompilasi, dan cara mengatasinya:
Kode | Pesan | Perbaikan |
---|---|---|
XC0022 |
Pengikatan dapat dikompilasi untuk meningkatkan performa runtime jika x:DataType ditentukan. |
Tambahkan x:DataType ke XAML Anda untuk menentukan jenis saat ini BindingContext. Praktik terbaik adalah menambahkan x:DataType ke semua elemen tempat konteks pengikatan berubah. |
XC0023 |
Pengikatan dapat dikompilasi untuk meningkatkan performa runtime jika x:DataType tidak secara null eksplisit . |
Ganti x:DataType="{x:Null}" dengan jenis yang tepat. |
Kode | Pesan |
---|---|
XC0022 |
Pengikatan dapat dikompilasi untuk meningkatkan performa runtime jika x:DataType ditentukan. Untuk memperbaiki peringatan ini, tambahkan x:DataType ke XAML Anda untuk menentukan jenis saat ini BindingContext. Praktik terbaik adalah menambahkan x:DataType ke semua elemen tempat konteks pengikatan berubah. |
XC0023 |
Pengikatan dapat dikompilasi untuk meningkatkan performa runtime jika x:DataType tidak secara null eksplisit . Untuk memperbaiki peringatan ini, ganti x:DataType="{x:Null}" dengan jenis yang tepat. |
XC0024 |
Pengikatan mungkin salah dikompilasi karena x:DataType anotasi berasal dari cakupan luar. Pastikan Anda membuat anotasi semua DataTemplate elemen XAML dengan yang benar x:DataType . Untuk memperbaiki peringatan ini, pastikan bahwa semua DataTemplate elemen diannotasi dengan yang benar x:DataType . |
XC0025 |
Pengikatan tidak dikompilasi karena memiliki properti yang diatur Source secara eksplisit dan kompilasi pengikatan dengan Source tidak diaktifkan. Pertimbangkan untuk mengaktifkan pengoptimalan ini dengan mengatur <MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> dalam file proyek Anda dan pastikan yang benar x:DataType ditentukan untuk pengikatan ini. Untuk memperbaiki peringatan ini, aktifkan $(MauiEnableXamlCBindingWithSourceCompilation) properti build di file proyek Anda, dan anotasi semua pengikatan Anda dengan yang sesuai x:DataType . |
Untuk memastikan peringatan ini tidak diabaikan, pertimbangkan untuk mengubah peringatan tertentu untuk membuat kesalahan dengan $(WarningsAsErrors)
properti build:
<WarningsAsErrors>$(WarningsAsErrors);XC0022;XC0023</WarningsAsErrors>
Untuk mengabaikan peringatan ini, gunakan $(NoWarn)
properti build dengan kode peringatan tertentu:
<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>
Penting
XC0022
dan XC0023
peringatan akan selalu ditekan kecuali $(MauiStrictXamlCompilation)
properti build diatur ke true
.
Jika Anda mengatur $(TreatWarningsAsErrors)
properti build ke true
dalam file proyek aplikasi, tetapi Anda ingin mengabaikan peringatan kompilator XAML tertentu, gunakan $(NoWarn)
properti build untuk membungkam peringatan ini atau $(WarningsNotAsErrors)
properti build untuk mengurangi tingkat keparahan beberapa kode tertentu.
Secara default, .NET MAUI menghasilkan peringatan build untuk pengikatan XAML yang tidak menggunakan pengikatan yang dikompilasi. Anda dapat memilih peringatan pengikatan yang dikompilasi yang diperlakukan sebagai kesalahan dengan mengatur $(MauiStrictXamlCompilation)
properti build dan $(TreatWarningsAsErrors)
ke true
dalam file proyek aplikasi Anda (*.csproj):
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MauiStrictXamlCompilation>true</MauiStrictXamlCompilation>
Catatan
Secara default, $(MauiStrictXamlCompilation)
properti build adalah false
kecuali Anda menerbitkan aplikasi menggunakan pemangkasan penuh atau NativeAOT.
Pengikatan yang dikompilasi dalam kode
Pengikatan yang ditulis dalam kode biasanya menggunakan jalur string yang diselesaikan pada runtime dengan pantulan. Namun, SetBinding metode ekstensi juga memiliki kelebihan beban yang menentukan pengikatan menggunakan Func
argumen alih-alih jalur string:
MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);
Tidak semua metode dapat digunakan untuk menentukan pengikatan yang dikompilasi. Ekspresi harus berupa ekspresi akses properti sederhana. Contoh berikut menunjukkan ekspresi pengikatan yang valid dan tidak valid:
// Valid: Property access
static (PersonViewModel vm) => vm.Name;
static (PersonViewModel vm) => vm.Address?.Street;
// Valid: Array and indexer access
static (PersonViewModel vm) => vm.PhoneNumbers[0];
static (PersonViewModel vm) => vm.Config["Font"];
// Valid: Casts
static (Label label) => (label.BindingContext as PersonViewModel).Name;
static (Label label) => ((PersonViewModel)label.BindingContext).Name;
// Invalid: Method calls
static (PersonViewModel vm) => vm.GetAddress();
static (PersonViewModel vm) => vm.Address?.ToString();
// Invalid: Complex expressions
static (PersonViewModel vm) => vm.Address?.Street + " " + vm.Address?.City;
static (PersonViewModel vm) => $"Name: {vm.Name}";
Selain itu, Binding.Create metode mengatur pengikatan langsung pada objek dengan Func
, dan mengembalikan instans objek pengikatan:
myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
Binding.Create(static (Entry entry) => entry.FontFamily, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontSize, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontAttributes, source: RelativeBindingSource.Self),
},
Converter = new StringConcatenationConverter()
});
Pendekatan pengikatan yang dikompilasi ini memberikan manfaat berikut:
- Meningkatkan performa pengikatan data dengan menyelesaikan ekspresi pengikatan pada waktu kompilasi daripada runtime.
- Pengalaman pemecahan masalah pengembang yang lebih baik karena pengikatan yang tidak valid dilaporkan sebagai kesalahan build.
- Intellisense saat mengedit.
Performa
Pengikatan yang dikompilasi meningkatkan performa pengikatan data, dengan manfaat performa bervariasi:
- Pengikatan terkompilasi yang menggunakan pemberitahuan perubahan properti (yaitu
OneWay
, ,OneWayToSource
atauTwoWay
pengikatan) diselesaikan sekitar 8 kali lebih cepat daripada pengikatan klasik. - Pengikatan terkompilasi yang tidak menggunakan pemberitahuan perubahan properti (yaitu
OneTime
pengikatan) diselesaikan sekitar 20 kali lebih cepat daripada pengikatan klasik. - BindingContext Mengatur pada pengikatan terkompilasi yang menggunakan pemberitahuan perubahan properti (yaitu
OneWay
, ,OneWayToSource
atauTwoWay
pengikatan) sekitar 5 kali lebih cepat daripada mengatur BindingContext pada pengikatan klasik. - BindingContext Mengatur pada pengikatan terkompilasi yang tidak menggunakan pemberitahuan perubahan properti (yaitu
OneTime
pengikatan) sekitar 7 kali lebih cepat daripada mengatur BindingContext pada pengikatan klasik.
Perbedaan performa ini dapat diperbesar pada perangkat seluler, tergantung pada platform yang digunakan, versi sistem operasi yang digunakan, dan perangkat tempat aplikasi berjalan.