Bagikan melalui


Pengikatan yang dikompilasi

Telusuri sampel. Telusuri sampel

Pengikatan data .NET Multi-platform App UI (.NET MAUI) memiliki dua masalah utama:

  1. 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.
  2. 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:

Pemilih warna yang dikompilasi.

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:

Daftar warna yang dikompilasi.

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

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, , OneWayToSourceatau TwoWay 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, , OneWayToSourceatau TwoWay 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.