Apa perbedaan antara properti ketergantungan dan properti terlampir di WPF?

Jawaban:

20

Abstrak

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

Kutipan kode

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
    });

Kesimpulan

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 RegisterAttachedparameter metadata diberi nama defaultMetadata, sedangkan untuk Registeritu dinamai typeMetadata. Untuk properti terlampir, metadata yang diberikan menjadi metadata default. Namun dalam kasus properti reguler, metadata default selalu merupakan instance baru PropertyMetadatadengan hanya DefaultValuedisetel (baik dari metadata yang disediakan atau otomatis). Hanya panggilan berikutnya untuk OverrideMetadatabenar - benar menggunakan metadata yang disediakan.

Konsekuensi

Perbedaan praktis utama adalah dalam kasus properti reguler, CoerceValueCallbackdan 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 OverrideMetadatamensyaratkan 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.).

Suplemen

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:

  • Sintaks nama implisit dapat digunakan pada elemen jika dan hanya jika kelas yang diwakili elemen ini memiliki properti CLR dari nama itu.
  • Sintaks nama eksplisit dapat digunakan pada elemen jika dan hanya jika kelas yang ditentukan oleh bagian pertama dari nama lengkap mengekspos metode get / set statis yang sesuai (disebut sebagai pengakses ) dengan nama yang cocok dengan bagian kedua dari nama lengkap

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.

Grx70
sumber
71

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.

Reed Copsey
sumber
10
Tapi apa sebenarnya perbedaannya ?! Dari apa yang saya lihat, Anda dapat melampirkan properti yang tidak dapat dilampirkan ke yang lain melalui kode (saya pikir ini diblokir di XAML.) Mungkin itu perbedaannya?
Mark A. Donohoe
5

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.

shweta
sumber
-1

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.

Mukesh
sumber
-1

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.

spspli
sumber