Bagikan melalui


Prioritas Nilai Properti Dependensi

Topik ini menjelaskan cara kerja sistem properti Windows Presentation Foundation (WPF) dapat memengaruhi nilai properti dependensi, dan menjelaskan prioritas di mana aspek sistem properti berlaku untuk nilai efektif properti.

Prasyarat

Topik ini mengasumsikan bahwa Anda memahami properti dependensi dari perspektif konsumen properti dependensi yang ada pada kelas WPF, dan telah membaca Gambaran Umum Properti Dependensi. Untuk mengikuti contoh dalam topik ini, Anda juga harus memahami XAML dan tahu cara menulis aplikasi WPF.

Sistem Properti WPF

Sistem properti WPF menawarkan cara yang kuat untuk memiliki nilai properti dependensi ditentukan oleh berbagai faktor, memungkinkan fitur seperti validasi properti real time, pengikatan terlambat, dan memberi tahu properti terkait tentang perubahan pada nilai untuk properti lain. Urutan dan logika yang tepat yang digunakan untuk menentukan nilai properti dependensi cukup kompleks. Mengetahui pesanan ini akan membantu Anda menghindari pengaturan properti yang tidak perlu, dan mungkin juga membersihkan kebingungan tentang persisnya mengapa beberapa upaya untuk memengaruhi atau mengantisipasi nilai properti dependensi tidak akhirnya menghasilkan nilai yang Anda harapkan.

Properti Dependensi Mungkin "Diatur" di Beberapa Tempat

Berikut ini adalah contoh XAML di mana properti yang sama (Background) memiliki tiga operasi "set" berbeda yang mungkin memengaruhi nilai.

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

Di sini, warna mana yang Anda harapkan akan berlaku—merah, hijau, atau biru?

Dengan pengecualian nilai animasi dan pemaksaan, set properti lokal diatur pada prioritas tertinggi. Jika Anda menetapkan nilai secara lokal, Anda dapat mengharapkan bahwa nilai akan dihormati, bahkan di atas gaya atau templat kontrol apa pun. Di sini dalam contoh, Background diatur ke Merah secara lokal. Oleh karena itu, gaya yang didefinisikan dalam cakupan ini, meskipun itu adalah gaya implisit yang jika tidak akan berlaku untuk semua elemen jenis tersebut dalam cakupan tersebut, bukanlah prioritas tertinggi untuk memberikan Background properti nilainya. Jika Anda menghapus nilai lokal Merah dari instans Tombol tersebut, gaya akan lebih diutamakan dan tombol akan mendapatkan nilai Latar Belakang dari gaya. Dalam gaya, pemicu lebih diutamakan, sehingga tombol akan berwarna biru jika mouse berada di atasnya, dan hijau jika tidak.

Daftar Prioritas Pengaturan Properti Dependensi

Berikut ini adalah urutan definitif yang digunakan sistem properti saat menetapkan nilai run-time properti dependensi. Prioritas tertinggi tercantum terlebih dahulu. Daftar ini diperluas pada beberapa generalisasi yang dibuat dalam Gambaran Umum Properti Dependensi.

  1. Koersi sistem properti. Untuk detail tentang paksaan, lihat Koersi, Animasi, dan Nilai Dasar nanti dalam topik ini.

  2. Animasi aktif, atau animasi dengan perilaku Tahan. Agar memiliki efek praktis, animasi properti harus dapat lebih diutamakan daripada nilai dasar (tidak dianimasikan), bahkan jika nilai tersebut ditetapkan secara lokal. Untuk detailnya, lihat Koersi, Animasi, dan Nilai Dasar nanti dalam topik ini.

  3. Nilai lokal. Nilai lokal mungkin diatur melalui kenyamanan properti "pembungkus", yang juga sama dengan pengaturan sebagai atribut atau elemen properti di XAML, atau dengan panggilan ke SetValue API menggunakan properti instans tertentu. Jika Anda menetapkan nilai lokal dengan menggunakan pengikatan atau sumber daya, masing-masing bertindak dalam prioritas seolah-olah nilai langsung ditetapkan.

  4. Properti templat TemplatedParent. Elemen memiliki TemplatedParent jika dibuat sebagai bagian dari templat ( ControlTemplate atau DataTemplate). Untuk detail tentang kapan ini berlaku, lihat TemplatedParent nanti dalam topik ini. Dalam templat, prioritas berikut berlaku:

    1. Pemicu dari TemplatedParent templat.

    2. Kumpulan properti (biasanya melalui atribut XAML) dalam TemplatedParent templat.

  5. Gaya implisit. Hanya berlaku untuk Style properti. Properti Style diisi oleh sumber daya gaya apa pun dengan kunci yang cocok dengan jenis elemen tersebut. Sumber daya gaya tersebut harus ada di halaman atau aplikasi; pencarian untuk sumber daya gaya implisit tidak melanjutkan ke tema.

  6. Pemicu gaya. Pemicu dalam gaya dari halaman atau aplikasi (gaya ini mungkin gaya eksplisit atau implisit, tetapi tidak dari gaya default, yang memiliki prioritas lebih rendah).

  7. Pemicu templat. Pemicu apa pun dari templat dalam gaya, atau templat yang diterapkan langsung.

  8. Setter gaya. Nilai dari Setter dalam gaya dari halaman atau aplikasi.

  9. Gaya (tema) default. Untuk detail tentang kapan ini berlaku, dan bagaimana gaya tema berhubungan dengan templat dalam gaya tema, lihat Gaya Default (Tema) nanti dalam topik ini. Dalam gaya default, urutan prioritas berikut berlaku:

    1. Pemicu aktif dalam gaya tema.

    2. Setter dalam gaya tema.

  10. Turunan. Beberapa properti dependensi mewarisi nilainya dari elemen induk ke elemen turunan, sehingga tidak perlu diatur secara khusus pada setiap elemen di seluruh aplikasi. Untuk detailnya, lihat Pewarisan Nilai Properti.

  11. Nilai default dari metadata properti dependensi. Properti dependensi tertentu mungkin memiliki nilai default seperti yang ditetapkan oleh pendaftaran sistem properti properti properti tertentu. Selain itu, kelas turunan yang mewarisi properti dependensi memiliki opsi untuk mengambil alih metadata tersebut (termasuk nilai default) berdasarkan per jenis. Lihat Metadata Properti Dependensi untuk informasi selengkapnya. Karena pewarisan diperiksa sebelum nilai default, untuk properti yang diwariskan, nilai default elemen induk lebih diutamakan daripada elemen turunan. Akibatnya, jika properti yang dapat diwariskan tidak diatur di mana pun, nilai default seperti yang ditentukan pada akar atau induk digunakan alih-alih nilai default elemen turunan.

TemplatedParent

TemplatedParent sebagai item prioritas tidak berlaku untuk properti elemen apa pun yang Anda deklarasikan langsung dalam markup aplikasi standar. Konsep TemplatedParent hanya ada untuk item anak dalam pohon visual yang muncul melalui aplikasi templat. Saat sistem properti mencari TemplatedParent nilai templat, sistem properti mencari nilai, sistem properti mencari templat yang membuat elemen tersebut. Nilai properti dari TemplatedParent templat umumnya bertindak seolah-olah ditetapkan sebagai nilai lokal pada elemen turunan, tetapi prioritas yang lebih rendah ini versus nilai lokal ada karena templat berpotensi dibagikan. Untuk detailnya, lihat TemplatedParent.

Properti Gaya

Urutan pencarian yang dijelaskan sebelumnya berlaku untuk semua properti dependensi yang mungkin kecuali satu: Style properti . Properti Style ini unik karena tidak dapat ditata dengan sendirinya, sehingga item prioritas 5 hingga 8 tidak berlaku. Selain itu, animasi atau koercing Style tidak disarankan (dan animasi Style akan memerlukan kelas animasi kustom). Ini menyisakan tiga cara agar Style properti dapat diatur:

  • Gaya eksplisit. Properti Style diatur secara langsung. Dalam sebagian besar skenario, gaya tidak didefinisikan sebaris, tetapi sebaliknya direferensikan sebagai sumber daya, dengan kunci eksplisit. Dalam hal ini properti Gaya itu sendiri bertindak seolah-olah itu adalah nilai lokal, item prioritas 3.

  • Gaya implisit. Properti Style tidak diatur secara langsung. Namun, Style ada pada tingkat tertentu dalam urutan pencarian sumber daya (halaman, aplikasi) dan di-key menggunakan kunci sumber daya yang cocok dengan jenis gaya yang akan diterapkan. Dalam hal ini, properti itu Style sendiri bertindak berdasarkan prioritas yang diidentifikasi dalam urutan sebagai item 5. Kondisi ini dapat dideteksi dengan menggunakan DependencyPropertyHelper terhadap Style properti dan mencari ImplicitStyleReference dalam hasilnya.

  • Gaya default, juga dikenal sebagai gaya tema. Properti Style tidak diatur secara langsung, dan sebenarnya akan dibaca hingga null run time. Dalam hal ini, gaya berasal dari evaluasi tema run-time yang merupakan bagian dari mesin presentasi WPF.

Untuk gaya implisit yang tidak dalam tema, jenis harus sama persis - MyButton Buttonkelas turunan tidak akan secara implisit menggunakan gaya untuk Button.

Gaya Default (Tema)

Setiap kontrol yang dikirim dengan WPF memiliki gaya default. Gaya default tersebut berpotensi bervariasi menurut tema, itulah sebabnya gaya default ini kadang-kadang disebut sebagai gaya tema.

Informasi terpenting yang ditemukan dalam gaya default untuk kontrol adalah templat kontrolnya, yang ada dalam gaya tema sebagai setter untuk propertinya Template . Jika tidak ada templat dari gaya default, kontrol tanpa templat kustom sebagai bagian dari gaya kustom tidak akan memiliki tampilan visual sama sekali. Templat dari gaya default memberikan tampilan visual setiap kontrol struktur dasar, dan juga menentukan koneksi antara properti yang ditentukan di pohon visual templat dan kelas kontrol yang sesuai. Setiap kontrol mengekspos sekumpulan properti yang dapat memengaruhi tampilan visual kontrol tanpa mengganti templat sepenuhnya. Misalnya, pertimbangkan tampilan Thumb visual default kontrol, yang merupakan komponen dari ScrollBar.

memiliki Thumb properti tertentu yang dapat disesuaikan. Templat default membuat Thumb struktur dasar / pohon visual dengan beberapa komponen berlapis Border untuk membuat tampilan kemiringan. Jika properti yang merupakan bagian dari templat dimaksudkan untuk diekspos untuk penyesuaian oleh kelas, maka properti tersebut Thumb harus diekspos oleh TemplateBinding, dalam templat. Dalam kasus Thumb, berbagai properti batas ini berbagi pengikatan templat ke properti seperti Background atau BorderThickness. Tetapi properti atau pengaturan visual tertentu lainnya dikodekan secara permanen ke dalam templat kontrol atau terikat ke nilai yang berasal langsung dari tema, dan tidak dapat diubah singkat mengganti seluruh templat. Umumnya, jika properti berasal dari induk templat dan tidak diekspos oleh pengikatan templat, properti tidak dapat disesuaikan oleh gaya karena tidak ada cara mudah untuk menargetkannya. Tetapi properti tersebut masih dapat dipengaruhi oleh pewarisan nilai properti dalam templat yang diterapkan, atau secara default.

Gaya tema menggunakan jenis sebagai kunci dalam definisinya. Namun, ketika tema diterapkan ke instans elemen tertentu, pencarian tema untuk jenis ini dilakukan dengan memeriksa DefaultStyleKey properti pada kontrol. Ini berbeda dengan menggunakan Jenis harfiah, seperti yang dilakukan gaya implisit. Nilai akan mewarisi kelas turunan DefaultStyleKey bahkan jika pelaksana tidak mengubahnya (cara yang dimaksudkan untuk mengubah properti bukan untuk menimpanya di tingkat properti, tetapi untuk mengubah nilai defaultnya dalam metadata properti). Tidak langsung ini memungkinkan kelas dasar untuk menentukan gaya tema untuk elemen turunan yang tidak memiliki gaya (atau yang lebih penting, tidak memiliki templat dalam gaya tersebut dan dengan demikian tidak akan memiliki tampilan visual default sama sekali). Dengan demikian, Anda dapat memperoleh MyButton dari Button dan masih akan mendapatkan Button templat default. Jika Anda adalah penulis MyButton kontrol dan Anda menginginkan perilaku yang berbeda, Anda dapat mengambil alih metadata properti dependensi untuk MyButton DefaultStyleKey mengembalikan kunci yang berbeda, lalu menentukan gaya tema yang relevan termasuk templat yang MyButton harus Anda kemas dengan kontrol AndaMyButton. Untuk detail selengkapnya tentang tema, gaya, dan penulisan kontrol, lihat Gambaran Umum Penulisan Kontrol.

Referensi dan Pengikatan Sumber Daya Dinamis

Referensi sumber daya dinamis dan operasi pengikatan menghormati prioritas lokasi di mana mereka ditetapkan. Misalnya, sumber daya dinamis yang diterapkan ke nilai lokal bertindak per item prioritas 3, pengikatan untuk setter properti dalam gaya tema berlaku pada item prioritas 9, dan sebagainya. Karena referensi sumber daya dinamis dan pengikatan keduanya harus dapat memperoleh nilai dari status run time aplikasi, ini mengharuskan bahwa proses aktual untuk menentukan nilai properti yang diutamakan untuk properti tertentu juga diperluas ke dalam run time.

Referensi sumber daya dinamis tidak secara ketat berbicara bagian dari sistem properti, tetapi mereka memiliki urutan pencarian sendiri yang berinteraksi dengan urutan yang tercantum di atas. Prioritas tersebut didokumentasikan lebih menyeluruh dalam Sumber Daya XAML. Penjumlahan dasar prioritas tersebut adalah: elemen ke akar halaman, aplikasi, tema, sistem.

Sumber daya dan pengikatan dinamis memiliki prioritas tempat sumber daya ditetapkan, tetapi 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 menggantikan sumber daya dinamis atau mengikat sepenuhnya. 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 dinamis atau pengikatan di tempat (tanpa nilai lokal harfiah), mereka juga dibersihkan oleh ClearValue panggilan.

SetCurrentValue

Metode SetCurrentValue ini adalah cara lain untuk mengatur properti, tetapi tidak dalam urutan prioritas. Sebaliknya, SetCurrentValue memungkinkan Anda mengubah nilai properti tanpa menimpa sumber nilai sebelumnya. Anda dapat menggunakan SetCurrentValue kapan saja yang ingin Anda tetapkan nilainya tanpa memberikan nilai tersebut prioritas nilai lokal. Misalnya, jika properti diatur oleh pemicu dan kemudian diberi nilai lain melalui SetCurrentValue, sistem properti masih menghormati pemicu dan properti akan berubah jika tindakan pemicu terjadi. SetCurrentValue memungkinkan Anda mengubah nilai properti tanpa memberinya sumber dengan prioritas yang lebih tinggi. Demikian juga, Anda dapat menggunakan SetCurrentValue untuk mengubah nilai properti tanpa menimpa pengikatan.

Koersi, Animasi, dan Nilai Dasar

Koersi dan animasi keduanya bertindak berdasarkan nilai yang disebut sebagai "nilai dasar" di seluruh SDK ini. Nilai dasar dengan demikian nilai apa pun ditentukan melalui mengevaluasi ke atas dalam item hingga item 2 tercapai.

Untuk animasi, nilai dasar dapat memiliki efek pada nilai animasi, jika animasi tersebut tidak menentukan "Dari" dan "Ke" untuk perilaku tertentu, atau jika animasi sengaja kembali ke nilai dasar ketika selesai. Untuk melihat ini dalam praktiknya, jalankan Sampel Dari, Ke, dan Menurut Nilai Target Animasi. Coba atur nilai lokal tinggi persegi panjang dalam contoh, sehingga nilai lokal awal berbeda dari "Dari" apa pun dalam animasi. Anda akan mencatat bahwa animasi segera dimulai menggunakan nilai "Dari" dan mengganti nilai dasar setelah dimulai. Animasi mungkin menentukan untuk kembali ke nilai yang ditemukan sebelum animasi setelah selesai dengan menentukan Hentikan FillBehavior. Setelah itu, prioritas normal digunakan untuk penentuan nilai dasar.

Beberapa animasi mungkin diterapkan ke satu properti, dengan masing-masing animasi ini mungkin telah ditentukan dari titik yang berbeda dalam nilai prioritas. Namun, animasi ini akan berpotensi menyusun nilainya, daripada hanya menerapkan animasi dari prioritas yang lebih tinggi. Ini tergantung pada persis bagaimana animasi didefinisikan, dan jenis nilai yang sedang dianimasikan. Untuk informasi selengkapnya tentang menganimasikan properti, lihat Gambaran Umum Animasi.

Koersi berlaku pada tingkat tertinggi dari semua. Bahkan animasi yang sudah berjalan tunduk pada koersi nilai. Properti dependensi tertentu yang ada di WPF memiliki paksaan bawaan. Untuk properti dependensi kustom, Anda menentukan perilaku koersi untuk properti dependensi kustom dengan menulis CoerceValueCallback dan meneruskan panggilan balik sebagai bagian dari metadata saat Anda membuat properti. Anda juga dapat mengambil alih perilaku pemakaian properti yang ada dengan mengambil alih metadata pada properti tersebut di kelas turunan. Koersi berinteraksi dengan nilai dasar sedih sehingga batasan pada paksaan diterapkan karena batasan tersebut ada pada saat itu, tetapi nilai dasar masih dipertahankan. Oleh karena itu, jika batasan dalam paksaan kemudian dicabut, koersi akan mengembalikan nilai terdekat yang mungkin dengan nilai dasar tersebut, 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 dalam tema. Mengatur properti lokal pada kontrol mungkin mencegah pemicu dapat merespons peristiwa yang digerakkan pengguna baik secara visual maupun perilaku. Penggunaan pemicu properti yang paling umum adalah untuk properti kontrol atau status seperti IsSelected. Misalnya, secara default ketika Button dinonaktifkan (pemicu untuk IsEnabled adalah false) maka Foreground nilai dalam gaya tema adalah apa yang menyebabkan kontrol muncul "berwarna abu-abu". Tetapi jika Anda telah menetapkan nilai lokal Foreground , warna abu-abu normal akan ditimpa diutamakan oleh kumpulan properti lokal Anda, bahkan dalam skenario yang dipicu properti ini. Berhati-hatilah dengan mengatur nilai untuk properti yang memiliki perilaku pemicu tingkat tema dan pastikan Anda tidak mengganggu pengalaman pengguna yang dimaksudkan untuk kontrol tersebut.

ClearValue dan Prioritas Nilai

Metode ini ClearValue menyediakan cara yang mudah untuk menghapus nilai yang diterapkan secara lokal dari properti dependensi yang diatur pada elemen. Namun, panggilan ClearValue bukan jaminan bahwa default seperti yang ditetapkan dalam metadata selama pendaftaran properti adalah nilai efektif baru. Semua peserta lain dalam prioritas nilai masih aktif. Hanya nilai yang ditetapkan secara lokal yang telah dihapus dari urutan prioritas. Misalnya, jika Anda memanggil ClearValue properti tempat properti tersebut juga diatur oleh gaya tema, maka nilai tema diterapkan sebagai nilai baru daripada default berbasis metadata. Jika Anda ingin mengeluarkan semua peserta nilai properti dari proses dan mengatur nilai ke default metadata terdaftar, Anda bisa mendapatkan nilai default tersebut secara definitif dengan mengkueri metadata properti dependensi, lalu Anda dapat menggunakan nilai default untuk mengatur properti secara lokal dengan panggilan ke SetValue.

Lihat juga