Apa perbedaan antara properti ketergantungan (khusus) dan properti terlampir di WPF? Apa kegunaan masing-masing? Apa perbedaan penerapannya?
Jawaban:
Karena saya tidak menemukan sedikit atau tidak ada dokumentasi tentang masalah ini, perlu sedikit mencari tahu tentang kode sumbernya , tetapi inilah jawabannya.
Ada perbedaan antara mendaftarkan properti dependensi sebagai properti reguler dan sebagai properti terlampir, selain properti "filosofis" ( properti reguler dimaksudkan untuk digunakan oleh tipe yang mendeklarasikan dan tipe turunannya, properti terlampir dimaksudkan untuk digunakan sebagai ekstensi pada DependencyObject
instance arbitrary ). "Filosofis", karena, seperti yang @MarqueIV perhatikan dalam komentarnya pada jawaban @ ReedCopsey, properti reguler juga dapat digunakan dengan DependencyObject
instance arbitrer .
Selain itu, saya harus tidak setuju dengan jawaban lain yang menyatakan bahwa properti terlampir adalah "tipe properti ketergantungan", karena menyesatkan - tidak ada "jenis" properti ketergantungan. Framework tidak peduli apakah properti itu terdaftar sebagai terlampir atau tidak - bahkan tidak mungkin untuk menentukannya (dalam arti bahwa informasi ini tidak direkam, karena tidak relevan). Faktanya, semua properti didaftarkan seolah-olah merupakan properti terlampir, tetapi dalam kasus properti biasa, beberapa hal tambahan dilakukan yang sedikit mengubah perilakunya.
Untuk menyelamatkan Anda dari masalah melalui kode sumber sendiri, berikut adalah versi singkat dari apa yang terjadi.
Saat mendaftarkan properti tanpa metadata yang ditentukan, memanggil
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
menghasilkan hasil yang sama persis dengan panggilan
DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
Namun, saat menentukan metadata, memanggil
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
setara dengan menelepon
var property = DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
defaultMetadata: new PropertyMetadata
{
DefaultValue = "default value",
});
property.OverrideMetadata(
forType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
Perbedaan utama (dan satu-satunya) antara properti dependensi reguler dan terlampir adalah metadata default yang tersedia melalui properti DependencyProperty.DefaultMetadata . Ini bahkan disebutkan di bagian Keterangan :
Untuk properti yang tidak terikat, tipe metadata yang dikembalikan oleh properti ini tidak dapat ditransmisikan ke tipe turunan dari tipe PropertyMetadata , bahkan jika properti tersebut awalnya terdaftar dengan tipe metadata turunan. Jika Anda ingin metadata asli yang terdaftar termasuk jenis metadata aslinya yang mungkin berasal, panggil GetMetadata (Type) sebagai gantinya, meneruskan jenis pendaftaran asli sebagai parameter.
Untuk properti terlampir, jenis metadata yang dikembalikan oleh properti ini akan cocok dengan jenis yang diberikan dalam metode pendaftaran RegisterAttached asli .
Ini terlihat jelas dalam kode yang disediakan. Petunjuk kecil juga disembunyikan dalam metode pendaftaran, yaitu untuk RegisterAttached
parameter metadata diberi nama defaultMetadata
, sedangkan untuk Register
itu dinamai typeMetadata
. Untuk properti terlampir, metadata yang diberikan menjadi metadata default. Namun dalam kasus properti reguler, metadata default selalu merupakan instance baru PropertyMetadata
dengan hanya DefaultValue
disetel (baik dari metadata yang disediakan atau otomatis). Hanya panggilan berikutnya untuk OverrideMetadata
benar - benar menggunakan metadata yang disediakan.
Perbedaan praktis utama adalah dalam kasus properti reguler, CoerceValueCallback
dan hanyaPropertyChangedCallback
berlaku untuk tipe yang diturunkan dari tipe yang dideklarasikan sebagai tipe pemilik, dan untuk properti terlampir, properti ini berlaku untuk semua tipe. Misalnya dalam skenario ini:
var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");
properti yang didaftarkan PropertyChangedCallback
akan dipanggil jika properti tersebut telah didaftarkan sebagai properti terlampir, tetapi tidak akan dipanggil jika telah didaftarkan sebagai properti biasa. Sama halnya CoerceValueCallback
.
Perbedaan sekunder berasal dari fakta yang OverrideMetadata
mensyaratkan bahwa jenis yang disediakan berasal DependencyObject
. Dalam praktiknya, ini berarti bahwa tipe pemilik untuk properti reguler harus diturunkan dari DependencyObject
, sedangkan untuk properti terlampir dapat berupa tipe apa saja (termasuk kelas statis, struct, enum, delegasi, dll.).
Selain saran @ MarqueIV, dalam beberapa kesempatan saya menemukan pendapat bahwa properti biasa dan terlampir berbeda dalam cara penggunaannya di XAML . Yakni, properti reguler tersebut memerlukan sintaks nama implisit sebagai lawan dari sintaks nama eksplisit yang diperlukan oleh properti terlampir. Ini secara teknis tidak benar , meskipun dalam praktiknya biasanya demikian. Untuk kejelasan:
<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" />
<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />
Dalam XAML murni , satu-satunya aturan yang mengatur penggunaan sintaks ini adalah sebagai berikut:
Dengan memenuhi ketentuan ini, Anda dapat menggunakan sintaks yang sesuai terlepas dari apakah properti ketergantungan dukungan telah didaftarkan sebagai reguler atau dilampirkan.
Sekarang kesalahpahaman yang disebutkan disebabkan oleh fakta bahwa sebagian besar tutorial (bersama dengan potongan kode Visual Studio stok ) menginstruksikan Anda untuk menggunakan properti CLR untuk properti dependensi reguler, dan dapatkan / setel aksesor untuk yang terlampir. Tetapi tidak ada yang menghentikan Anda untuk menggunakan keduanya secara bersamaan, memungkinkan Anda menggunakan sintaks mana pun yang Anda inginkan.
Properti terlampir adalah jenis properti ketergantungan. Perbedaannya terletak pada cara penggunaannya.
Dengan properti terlampir, properti didefinisikan pada kelas yang bukan kelas yang sama yang digunakannya. Ini biasanya digunakan untuk tata letak. Contoh yang bagus adalah Panel.ZIndex atau Grid.Row - Anda menerapkan ini ke kontrol (yaitu: Tombol), tetapi sebenarnya ditentukan di Panel atau Grid. Properti ini "dilampirkan" ke instance tombol.
Ini memungkinkan sebuah wadah, misalnya, untuk membuat properti yang dapat digunakan pada elemen UI apa pun.
Adapun perbedaan implementasi - pada dasarnya hanya masalah menggunakan Register vs. RegisterAttached saat Anda mendefinisikan properti.
Properti terlampir pada dasarnya dimaksudkan untuk elemen kontainer. Seperti jika Anda memiliki grid dan Anda memiliki grid.row sekarang ini dianggap sebagai properti terlampir dari elemen grid. Anda juga dapat menggunakan properti ini di texbox, tombol dll untuk menyetelnya tempatkan di grid.
Properti dependensi seperti properti pada dasarnya milik beberapa kelas lain dan digunakan di kelas lain. misalnya: seperti Anda memiliki persegi panjang di sini tinggi dan lebar adalah properti persegi panjang biasa, tetapi left dan top adalah properti dependensi karena termasuk dalam kelas Canvass.
Properti terlampir adalah jenis khusus dari DependencyProperties. Mereka memungkinkan Anda untuk melampirkan nilai ke objek yang tidak tahu apa-apa tentang nilai ini. Contoh yang baik untuk konsep ini adalah panel tata letak. Setiap panel tata letak membutuhkan data yang berbeda untuk menyelaraskan elemen anaknya. Kanvas membutuhkan Atas dan Kiri, DockPanel membutuhkan Dock, dll. Karena Anda dapat menulis panel tata letak Anda sendiri, daftarnya tidak terbatas. Jadi Anda tahu, tidak mungkin memiliki semua properti itu di semua kontrol WPF. Solusinya adalah properti terlampir. Mereka ditentukan oleh kontrol yang membutuhkan data dari kontrol lain dalam konteks tertentu. Misalnya elemen yang disejajarkan dengan panel tata letak induk.
Saya pikir Anda dapat mendefinisikan properti terlampir di kelas itu sendiri atau Anda dapat menentukannya di kelas lain. Kami selalu dapat menggunakan properti terlampir untuk memperluas kontrol microsoft standar. Tetapi properti ketergantungan, Anda menentukannya dalam kontrol kustom Anda sendiri. misalnya Anda dapat mewarisi kontrol Anda dari kontrol standar, dan menentukan properti ketergantungan dalam kontrol Anda sendiri dan menggunakannya. Ini sama dengan mendefinisikan properti terlampir, dan menggunakan properti terlampir ini dalam kontrol standar.