Bagikan melalui


Prioritas nilai properti dependensi (WPF .NET)

Pekerjaan sistem properti Windows Presentation Foundation (WPF) memengaruhi nilai properti dependensi. Artikel ini menjelaskan bagaimana prioritas input berbasis properti yang berbeda dalam sistem properti WPF menentukan nilai efektif properti dependensi.

Penting

Dokumentasi Panduan Desktop untuk .NET 7 dan .NET 6 sedang dibangun.

Prasyarat

Artikel ini mengasumsikan pengetahuan dasar tentang properti dependensi, dan bahwa Anda telah membaca gambaran umum properti Dependensi. Untuk mengikuti contoh dalam artikel ini, ini membantu jika Anda terbiasa dengan Extensible Application Markup Language (XAML) dan tahu cara menulis aplikasi WPF.

Sistem properti WPF

Sistem properti WPF menggunakan berbagai faktor untuk menentukan nilai properti dependensi, seperti validasi properti real time, pengikatan terlambat, dan pemberitahuan perubahan properti untuk properti terkait. Meskipun urutan dan logika yang digunakan untuk menentukan nilai properti dependensi kompleks, mempelajarinya dapat membantu Anda menghindari pengaturan properti yang tidak perlu, dan juga untuk mencari tahu mengapa upaya untuk menetapkan properti dependensi tidak menghasilkan nilai yang diharapkan.

Properti dependensi diatur di beberapa tempat

Contoh XAML berikut menunjukkan bagaimana tiga operasi "set" yang berbeda pada properti tombol Background dapat memengaruhi nilainya.

<StackPanel>
    <StackPanel.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" 
                    BorderBrush="{TemplateBinding BorderBrush}">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Border>
        </ControlTemplate>
    </StackPanel.Resources>

    <Button Template="{StaticResource ButtonTemplate}" Background="Red">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="Blue"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="Yellow" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
        Which color do you expect?
    </Button>
</StackPanel>

Dalam contoh, Background properti diatur secara lokal ke Red. Namun, gaya implisit yang dideklarasikan dalam cakupan tombol, mencoba mengatur properti ke BackgroundBlue. Dan, ketika mouse berada di atas tombol, pemicu dalam gaya implisit mencoba mengatur Background properti ke Yellow. Kecuali untuk paksaan dan animasi, nilai properti yang ditetapkan secara lokal memiliki prioritas tertinggi, sehingga tombol akan berwarna merah—bahkan pada mouseover. Tetapi, jika Anda menghapus nilai yang ditetapkan secara lokal dari tombol, maka nilainya akan mendapatkan nilainya Background dari gaya. Dalam gaya, pemicu lebih diutamakan, sehingga tombol akan berwarna kuning pada mouseover, dan biru jika tidak. Contoh menggantikan default ControlTemplate tombol karena templat default memiliki nilai mouseover Background yang dikodekan secara permanen.

Daftar prioritas properti dependensi

Daftar berikut adalah urutan prioritas definitif yang digunakan sistem properti saat menetapkan nilai runtime ke properti dependensi. Prioritas tertinggi tercantum terlebih dahulu.

  1. Koersi sistem properti. Untuk informasi selengkapnya tentang paksaan, lihat Koersi dan animasi.

  2. Animasi aktif, atau animasi dengan perilaku Tahan. Untuk memiliki efek praktis, nilai animasi harus lebih diutamakan daripada nilai dasar (tidak dianimasikan), bahkan jika nilai dasar diatur secara lokal. Untuk informasi selengkapnya, lihat Koersi dan animasi.

  3. Nilai lokal. Anda dapat mengatur nilai lokal melalui properti "wrapper", yang sama dengan mengatur atribut atau elemen properti di XAML, atau dengan panggilan ke SetValue API menggunakan properti instans tertentu. Nilai lokal yang ditetapkan melalui pengikatan atau sumber daya akan memiliki prioritas yang sama dengan nilai yang diatur langsung.

  4. Nilai properti templat TemplatedParent. Elemen memiliki TemplatedParent jika dibuat oleh templat (ControlTemplate atau DataTemplate). Untuk informasi selengkapnya, lihat TemplatedParent. Dalam templat yang ditentukan oleh TemplatedParent, urutan prioritas adalah:

    1. Pemicu.

    2. Kumpulan properti, biasanya melalui atribut XAML.

  5. Gaya implisit. Hanya berlaku untuk Style properti. Nilainya Style adalah sumber daya gaya apa pun dengan nilai yang cocok dengan TargetType jenis elemen. Sumber daya gaya harus ada di dalam halaman atau aplikasi. Cari sumber daya gaya implisit tidak meluas ke sumber daya gaya dalam Tema.

  6. Pemicu gaya. Pemicu gaya adalah pemicu dalam gaya eksplisit atau implisit. Gaya harus ada di dalam halaman atau aplikasi. Pemicu dalam gaya default memiliki prioritas yang lebih rendah.

  7. Pemicu templat. Pemicu templat adalah pemicu dari templat yang diterapkan langsung, atau dari templat dalam gaya. Gaya harus ada di dalam halaman atau aplikasi.

  8. Nilai setter gaya. Nilai setter gaya adalah nilai yang diterapkan oleh Setter dalam gaya. Gaya harus ada di dalam halaman atau aplikasi.

  9. Gaya default, juga dikenal sebagai gaya tema. Untuk informasi selengkapnya, lihat Gaya default (Tema). Dalam gaya default, urutan prioritasnya adalah:

    1. Pemicu aktif.

    2. Setter.

  10. Warisan. Beberapa properti dependensi elemen anak mewarisi nilainya dari elemen induk. Jadi, mungkin tidak perlu mengatur nilai properti pada setiap elemen di seluruh aplikasi. Untuk informasi selengkapnya, lihat Pewarisan nilai properti.

  11. Nilai default dari metadata properti dependensi Properti dependensi dapat memiliki nilai default yang ditetapkan selama pendaftaran sistem properti properti tersebut. Kelas turunan yang mewarisi properti dependensi dapat mengambil alih metadata properti dependensi (termasuk nilai default) per jenis. Untuk informasi selengkapnya, lihat Metadata properti dependensi. Untuk properti yang diwariskan, nilai default elemen induk lebih diutamakan daripada nilai default elemen turunan. Jadi, jika properti yang dapat diwariskan tidak diatur, nilai default akar atau induk digunakan alih-alih nilai default elemen turunan.

TemplatedParent

TemplatedParent prioritas tidak berlaku untuk properti elemen yang dideklarasikan langsung dalam markup aplikasi standar. Konsep hanya TemplatedParent ada untuk item anak dalam pohon visual yang muncul melalui aplikasi templat. Saat sistem properti mencari templat yang ditentukan oleh TemplatedParent untuk nilai properti elemen, sistem properti mencari templat yang membuat elemen. Nilai properti dari TemplatedParent templat umumnya bertindak seolah-olah nilai ditetapkan secara lokal pada elemen , tetapi dengan prioritas yang lebih rendah daripada nilai lokal aktual karena templat berpotensi dibagikan. Untuk informasi selengkapnya, lihat TemplatedParent .

Properti Gaya

Urutan prioritas yang sama berlaku untuk semua properti dependensi, kecuali Style properti . Properti Style ini unik karena tidak dapat ditata dengan sendirinya. Memaksakan atau menganimasikan Style properti tidak disarankan (dan menganimasikan Style properti akan memerlukan kelas animasi kustom). Akibatnya, tidak semua item prioritas berlaku. Hanya ada tiga cara untuk mengatur Style properti:

  • Gaya eksplisit. Properti Style elemen diatur secara langsung. Nilai Style properti bertindak seolah-olah itu adalah nilai lokal dan memiliki prioritas yang sama dengan item 3 dalam daftar prioritas. Dalam sebagian besar skenario, gaya eksplisit tidak didefinisikan sebaris dan sebaliknya secara eksplisit direferensikan sebagai sumber daya, misalnya Style="{StaticResource myResourceKey}".

  • Gaya implisit. Properti Style elemen tidak diatur secara langsung. Sebaliknya, gaya diterapkan ketika ada di beberapa tingkat dalam halaman atau aplikasi, dan memiliki kunci sumber daya yang cocok dengan jenis elemen yang diterapkan gaya, misalnya <Style TargetType="x:Type Button">. Jenis harus sama persis, misalnya <Style TargetType="x:Type Button"> tidak akan diterapkan ke MyButton jenis bahkan jika MyButton berasal dari Button. Nilai Style properti memiliki prioritas yang sama dengan item 5 dalam daftar prioritas. Nilai gaya implisit dapat dideteksi dengan memanggil DependencyPropertyHelper.GetValueSource metode, meneruskan Style properti, dan memeriksa ImplicitStyleReference hasilnya.

  • Gaya default, juga dikenal sebagai gaya tema. Properti Style elemen tidak diatur secara langsung. Sebaliknya, itu berasal dari evaluasi tema runtime oleh mesin presentasi WPF. Sebelum runtime, Style nilai properti adalah null. Nilai Style properti memiliki prioritas yang sama dengan item 9 dalam daftar prioritas.

Gaya default (Tema)

Setiap kontrol yang dikirim dengan WPF memiliki gaya default yang dapat bervariasi menurut tema, itulah sebabnya gaya default terkadang disebut sebagai gaya tema.

ControlTemplate adalah item penting dalam gaya default untuk kontrol. ControlTemplate adalah nilai setter untuk properti gaya Template . Jika gaya default tidak berisi templat, kontrol tanpa templat kustom sebagai bagian dari gaya kustom tidak akan memiliki tampilan visual. Templat tidak hanya menentukan tampilan visual kontrol, templat juga menentukan koneksi antara properti di pohon visual templat dan kelas kontrol yang sesuai. Setiap kontrol mengekspos sekumpulan properti yang dapat memengaruhi tampilan visual kontrol tanpa mengganti templat. Misalnya, pertimbangkan tampilan Thumb visual default kontrol, yang merupakan ScrollBar komponen.

Thumb Kontrol memiliki properti tertentu yang dapat disesuaikan. Templat Thumb default kontrol membuat struktur dasar, atau pohon visual, dengan beberapa komponen berlapis Border untuk membuat tampilan kemiringan. Dalam templat, properti yang dimaksudkan untuk dapat disesuaikan oleh Thumb kelas diekspos melalui TemplateBinding. Templat default untuk Thumb kontrol memiliki berbagai properti batas yang berbagi pengikatan templat dengan properti seperti Background atau BorderThickness. Tetapi, di mana nilai untuk properti atau pengaturan visual dikodekan secara permanen dalam templat, atau terikat ke nilai yang berasal langsung dari tema, Anda hanya dapat mengubah nilai tersebut dengan mengganti seluruh templat. Umumnya, jika properti berasal dari induk templat dan tidak diekspos oleh TemplateBinding, maka nilai properti tidak dapat diubah oleh gaya karena tidak ada cara mudah untuk menargetkannya. Namun, properti tersebut mungkin masih dipengaruhi oleh pewarisan nilai properti dalam templat yang diterapkan, atau dengan nilai default.

Gaya default menentukan TargetType dalam definisinya. Evaluasi tema runtime cocok dengan TargetType gaya default dengan DefaultStyleKey properti kontrol. Sebaliknya, perilaku pencarian untuk gaya implisit menggunakan jenis kontrol yang sebenarnya. Nilai diwariskan oleh kelas turunan, sehingga elemen turunan DefaultStyleKey yang mungkin tidak memiliki gaya terkait mendapatkan tampilan visual default. Misalnya, jika Anda berasal MyButton dari Button, MyButton akan mewarisi templat default .Button Kelas turunan dapat mengambil alih nilai DefaultStyleKey default dalam metadata properti dependensi. Jadi, jika Anda menginginkan representasi visual yang berbeda untuk MyButton, Anda dapat mengambil alih metadata properti dependensi untuk DefaultStyleKey pada MyButton, lalu menentukan gaya default yang relevan termasuk templat, yang akan Anda kemas dengan kontrol Anda MyButton . Untuk informasi selengkapnya, lihat Gambaran umum penulisan kontrol.

Sumber daya dinamis

Referensi sumber daya dinamis dan operasi pengikatan memiliki prioritas lokasi di mana mereka ditetapkan. Misalnya, sumber daya dinamis yang diterapkan ke nilai lokal memiliki prioritas yang sama dengan item 3 dalam daftar prioritas. Sebagai contoh lain, pengikatan sumber daya dinamis yang diterapkan ke setter properti dalam gaya default memiliki prioritas yang sama dengan item 9 dalam daftar prioritas. Karena referensi dan pengikatan sumber daya dinamis harus mendapatkan nilai dari status runtime aplikasi, proses untuk menentukan nilai properti yang diutamakan untuk properti tertentu diperluas menjadi runtime.

Referensi sumber daya dinamis bukan bagian teknis dari sistem properti, dan memiliki urutan pencarian mereka sendiri yang berinteraksi dengan daftar prioritas. Pada dasarnya, prioritas referensi sumber daya dinamis adalah: elemen ke akar halaman, aplikasi, tema, dan kemudian sistem. Untuk informasi selengkapnya, lihat Sumber Daya XAML.

Meskipun referensi dan pengikatan sumber daya dinamis memiliki prioritas lokasi yang ditetapkan, nilainya ditangguhkan. Salah satu konsekuensi dari ini adalah bahwa jika Anda mengatur sumber daya dinamis atau mengikat ke nilai lokal, setiap perubahan pada nilai lokal sepenuhnya menggantikan sumber daya atau pengikatan dinamis. Bahkan jika Anda memanggil ClearValue metode untuk menghapus nilai yang ditetapkan secara lokal, sumber daya atau pengikatan dinamis tidak akan dipulihkan. Bahkan, jika Anda memanggil ClearValue properti yang memiliki sumber daya atau pengikatan dinamis (tanpa nilai lokal harfiah), sumber daya dinamis atau pengikatan akan dihapus.

SetCurrentValue

Metode SetCurrentValue ini adalah cara lain untuk mengatur properti, tetapi tidak ada dalam daftar prioritas. SetCurrentValue memungkinkan Anda mengubah nilai properti tanpa menimpa sumber nilai sebelumnya. Misalnya, jika properti diatur oleh pemicu, lalu Anda menetapkan nilai lain menggunakan SetCurrentValue, tindakan pemicu berikutnya akan mengatur properti kembali ke nilai pemicu. Anda dapat menggunakan SetCurrentValue kapan pun Anda ingin menetapkan nilai properti tanpa memberikan nilai tersebut tingkat prioritas nilai lokal. Demikian pula, Anda dapat menggunakan SetCurrentValue untuk mengubah nilai properti tanpa menimpa pengikatan.

Koersi dan animasi

Koersi dan animasi keduanya bertindak berdasarkan nilai dasar. Nilai dasar adalah nilai properti dependensi dengan prioritas tertinggi, ditentukan dengan mengevaluasi ke atas melalui daftar prioritas hingga item 2 tercapai.

Jika animasi tidak menentukan From nilai properti dan To untuk perilaku tertentu, atau jika animasi sengaja kembali ke nilai dasar saat selesai, maka nilai dasar dapat memengaruhi nilai animasi. Untuk melihat ini dalam praktiknya, jalankan aplikasi sampel Nilai Target. Dalam sampel, untuk tinggi persegi panjang, coba atur nilai lokal awal yang berbeda dari nilai apa pun From . Animasi sampel segera dimulai dengan menggunakan From nilai alih-alih nilai dasar. Dengan menentukan Stop sebagai FillBehavior, pada penyelesaian animasi akan mengatur ulang nilai properti ke nilai dasarnya. Prioritas normal digunakan untuk penentuan nilai dasar setelah animasi berakhir.

Beberapa animasi dapat diterapkan ke satu properti, dengan setiap animasi memiliki prioritas yang berbeda. Daripada menerapkan animasi dengan prioritas tertinggi, mesin presentasi WPF mungkin menggabungkan nilai animasi, tergantung pada bagaimana animasi ditentukan dan jenis nilai yang dianimasikan. Untuk informasi lebih lanjut, lihat Gambaran Umum animasi.

Pemaksaan berada di bagian atas daftar prioritas. Bahkan animasi yang sedang berjalan tunduk pada koersi nilai. Beberapa properti dependensi yang ada di WPF memiliki koersi bawaan. Untuk properti dependensi kustom, Anda dapat menentukan perilaku koersi dengan menulis CoerceValueCallback yang Anda lewati sebagai bagian dari metadata saat membuat properti. Anda juga dapat mengambil alih perilaku koersi properti yang ada dengan mengambil alih metadata untuk properti tersebut di kelas turunan. Koersi berinteraksi dengan nilai dasar sedih sehingga batasan pada paksaan diterapkan seperti yang ada pada saat itu, tetapi nilai dasar masih dipertahankan. Akibatnya, jika batasan dalam paksaan kemudian dicabut, paksaan akan mengembalikan nilai terdekat yang mungkin dengan nilai dasar, dan berpotensi pengaruh paksaan pada properti akan berhenti segera setelah semua batasan diangkat. Untuk informasi selengkapnya tentang perilaku koersi, lihat Panggilan balik dan validasi properti dependensi.

Perilaku pemicu

Kontrol sering menentukan perilaku pemicu sebagai bagian dari gaya defaultnya. Mengatur properti lokal pada kontrol dapat berpotensi bertentangan dengan pemicu tersebut, mencegah pemicu merespons (baik secara visual atau perilaku) ke peristiwa yang digerakkan pengguna. Penggunaan umum pemicu properti adalah untuk mengontrol properti status, seperti IsSelected atau IsEnabled. Misalnya, secara default, saat Button dinonaktifkan, pemicu gaya tema (IsEnabled adalah false) mengatur Foreground nilai untuk membuat Button tampilan berwarna abu-abu. Jika Anda telah menetapkan nilai lokal Foreground , nilai properti lokal prioritas yang lebih tinggi akan menimpa nilai gaya Foreground tema, bahkan saat dinonaktifkan Button . Saat mengatur nilai properti yang mengambil alih perilaku pemicu tingkat tema untuk kontrol, berhati-hatilah untuk tidak mengganggu pengalaman pengguna yang dimaksudkan untuk kontrol tersebut.

ClearValue

Metode ini ClearValue menghapus nilai properti dependensi yang diterapkan secara lokal untuk elemen. Tetapi, panggilan ClearValue tidak menjamin bahwa nilai default yang ditetapkan dalam metadata selama pendaftaran properti adalah nilai efektif baru. Semua peserta lain dalam daftar prioritas masih aktif, dan hanya nilai yang ditetapkan secara lokal yang dihapus. Misalnya, jika Anda memanggil ClearValue properti yang memiliki gaya tema, nilai gaya tema akan diterapkan sebagai nilai baru, bukan default berbasis metadata. Jika Anda ingin mengatur nilai properti ke nilai default metadata terdaftar, dapatkan nilai metadata default dengan mengkueri metadata properti dependensi, dan atur nilai properti secara lokal dengan panggilan ke SetValue.

Baca juga