Jaka jest różnica między właściwością zależności a dołączoną właściwością w WPF?

91

Jaka jest różnica między (niestandardową) właściwością zależności a dołączoną właściwością w WPF? Jakie są zastosowania każdego z nich? Czym zazwyczaj różnią się implementacje?

kenwarner
źródło

Odpowiedzi:

20

Abstrakcyjny

Ponieważ nie znalazłem niewiele dokumentacji w tej sprawie, zajęło to trochę grzebania w kodzie źródłowym , ale oto odpowiedź.

Istnieje różnica między rejestrowaniem właściwości zależności jako zwykłej i jako dołączonej właściwości, innej niż „filozoficzna” ( zwykłe właściwości są przeznaczone do użycia przez deklarujący typ i jego typy pochodne, dołączone właściwości mają być używane jako rozszerzenia w dowolnych DependencyObject instancjach ). „Filozoficzne”, ponieważ, jak zauważył @MarqueIV w swoim komentarzu do odpowiedzi @ ReedCopsey, zwykłe właściwości mogą być również używane z dowolnymi DependencyObjectinstancjami.

Co więcej, muszę nie zgodzić się z innymi odpowiedziami, które stwierdzają, że dołączona właściwość jest „typem właściwości zależności”, ponieważ wprowadza w błąd - nie ma żadnych „typów” właściwości zależności. Framework nie dba o to, czy nieruchomość została zarejestrowana jako zajęta, czy nie - nie jest nawet możliwe do ustalenia (w tym sensie, że ta informacja nie jest rejestrowana, ponieważ jest nieistotna). W rzeczywistości wszystkie właściwości są rejestrowane tak, jakby były dołączonymi właściwościami, ale w przypadku zwykłych robione są dodatkowe rzeczy, które nieznacznie modyfikują ich zachowanie.

Fragment kodu

Aby zaoszczędzić Ci kłopotów związanych z samodzielnym przeglądaniem kodu źródłowego, oto skrócona wersja tego, co się dzieje.

Podczas rejestrowania właściwości bez określonych metadanych, wywołanie

DependencyProperty.Register(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass))

daje dokładnie taki sam wynik jak wywołanie

DependencyProperty.RegisterAttached(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass))

Jednak podczas określania metadanych wywołanie

DependencyProperty.Register(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass),
    typeMetadata: new FrameworkPropertyMetadata
    {
        CoerceValueCallback = CoerceCallback,
        DefaultValue = "default value",
        PropertyChangedCallback = ChangedCallback
    });

jest równoznaczne z dzwonieniem

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

Wnioski

Kluczową (i jedyną) różnicą między zwykłymi i dołączonymi właściwościami zależności są domyślne metadane dostępne za pośrednictwem właściwości DependencyProperty.DefaultMetadata . Jest to nawet wspomniane w sekcji Uwagi :

W przypadku właściwości niedołączonych typ metadanych zwracany przez tę właściwość nie może być rzutowany na typy pochodne typu PropertyMetadata , nawet jeśli właściwość została pierwotnie zarejestrowana przy użyciu typu pochodnych metadanych. Jeśli chcesz, aby pierwotnie zarejestrowane metadane, w tym ich oryginalny, prawdopodobnie pochodny typ metadanych, zamiast tego wywołaj GetMetadata (Type) , przekazując oryginalny typ rejestracji jako parametr.

W przypadku dołączonych właściwości typ metadanych zwracanych przez tę właściwość będzie zgodny z typem podanym w oryginalnej metodzie rejestracji RegisterAttached .

Jest to wyraźnie widoczne w dostarczonym kodzie. Drobne wskazówki są też ukryte w metodach rejestracji, tj. Dla RegisterAttachedparametru metadata jest nazwany defaultMetadata, a dla Registerniego nazwany typeMetadata. W przypadku dołączonych właściwości podane metadane stają się metadanymi domyślnymi. Jednak w przypadku zwykłych właściwości, domyślne metadane są zawsze świeżą instancją PropertyMetadatatylko z DefaultValueustawieniem (z podanych metadanych lub automatycznie). Dopiero kolejne wywołanie OverrideMetadatafaktycznie korzysta z podanych metadanych.

Konsekwencje

Główna praktyczna różnica polega na tym, że w przypadku zwykłych właściwości, CoerceValueCallbacki PropertyChangedCallbackmają zastosowanie tylko do typów pochodzących z typu zadeklarowanego jako typ właściciela, a do dołączonych właściwości mają zastosowanie do wszystkich typów. Np. W tym scenariuszu:

var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");

osoba wpisana do rejestru PropertyChangedCallback zostanie wywołana, jeśli nieruchomość została zarejestrowana jako nieruchomość zajęta, ale nie zostanie wywołana, jeśli została zarejestrowana jako nieruchomość zwykła. To samo dotyczy CoerceValueCallback.

Drugorzędna różnica wynika z faktu, że OverrideMetadatawymaga, aby typ dostarczony pochodzi z DependencyObject. W praktyce oznacza to, że typ właściciela dla zwykłych właściwości musi pochodzić z DependencyObject, podczas gdy dla dołączonych właściwości w może być dowolny typ (w tym klasy statyczne, struktury, wyliczenia, delegaty itp.).

Suplement

Oprócz sugestii @ MarqueIV, przy kilku okazjach spotkałem się z opiniami, że zwykłe i dołączone właściwości różnią się sposobem, w jaki mogą być używane w XAML . Mianowicie, te zwykłe właściwości wymagają niejawnej składni nazwy, w przeciwieństwie do jawnej składni nazw wymaganej przez dołączone właściwości. Technicznie nie jest to prawdą , chociaż w praktyce zwykle tak jest. Dla jasności:

<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" /> 

<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />

W czystym języku XAML jedyne reguły regulujące użycie tych składni są następujące:

  • Niejawna składnia nazwy może być używana w elemencie wtedy i tylko wtedy, gdy klasa, którą reprezentuje ten element, ma właściwość CLR o tej nazwie
  • Jawną składnię nazwy można zastosować w elemencie wtedy i tylko wtedy, gdy klasa określona przez pierwszą część pełnej nazwy udostępnia odpowiednie statyczne metody get / set (nazywane akcesorami ) z nazwami pasującymi do drugiej części pełnej nazwy

Spełnienie tych warunków umożliwia użycie odpowiedniej składni niezależnie od tego, czy właściwość zależności kopii zapasowej została zarejestrowana jako zwykła, czy dołączona.

Teraz wspomniane nieporozumienie jest spowodowane faktem, że zdecydowana większość samouczków (wraz z fragmentami kodu standardowego programu Visual Studio ) instruuje Cię, aby użyć właściwości CLR dla zwykłych właściwości zależności i pobrać / ustawić metody dostępu dla dołączonych. Ale nic nie stoi na przeszkodzie, abyś używał obu jednocześnie, umożliwiając użycie dowolnej preferowanej składni.

Grx70
źródło
71

Dołączone właściwości są typem właściwości zależności. Różnica polega na tym, jak są używane.

W przypadku dołączonej właściwości właściwość jest zdefiniowana w klasie, która nie jest tą samą klasą, dla której jest używana. Jest to zwykle używane do układu. Dobrymi przykładami są Panel.ZIndex lub Grid.Row - stosujesz to do kontrolki (np .: Button), ale tak naprawdę jest ona zdefiniowana w Panel lub Grid. Właściwość jest „dołączona” do instancji przycisku.

Umożliwia to na przykład kontenerowi tworzenie właściwości, które mogą być używane w dowolnym elemencie interfejsu użytkownika.

Jeśli chodzi o różnice implementacyjne - to po prostu kwestia użycia Register vs RegisterAttached podczas definiowania właściwości.

Reed Copsey
źródło
10
Ale na czym dokładnie polega różnica ?! Z tego, co widziałem, można dołączyć właściwość, której nie można dołączyć, do innej za pomocą kodu (myślę, że jest to jednak blokowane w XAML). Być może na tym polega różnica?
Mark A. Donohoe,
5

Załączone właściwości są zasadniczo przeznaczone dla elementów kontenera. Na przykład jeśli masz siatkę i masz grid. Teraz jest to uważane za dołączoną właściwość elementu siatki. Możesz również użyć tej właściwości w texbox, przycisku itp., Aby ustawić jej umieścić w siatce.

Właściwość zależności jest podobna do tej, która zasadniczo należy do innej klasy i jest używana w innej klasie. np .: tak jak masz tutaj prostokąt, wysokość i szerokość są zwykłymi właściwościami prostokąta, ale left i top są właściwościami zależności, ponieważ należą do klasy Canvass.

shweta
źródło
-1

Dołączone właściwości są specjalnym rodzajem DependencyProperties. Umożliwiają one przypisanie wartości do obiektu, który nic nie wie o tej wartości. Dobrym przykładem tej koncepcji są panele układu. Każdy panel układu wymaga innych danych, aby wyrównać elementy podrzędne. Płótno wymaga górnej i lewej strony, DockPanel wymaga Docka itp. Ponieważ możesz napisać własny panel układu, lista jest nieskończona. Więc widzisz, nie jest możliwe, aby mieć wszystkie te właściwości na wszystkich kontrolkach WPF. Rozwiązaniem są dołączone właściwości. Są definiowane przez formant, który potrzebuje danych z innego formantu w określonym kontekście. Na przykład element wyrównany przez nadrzędny panel układu.

Mukesh
źródło
-1

Myślę, że możesz zdefiniować dołączoną właściwość w samej klasie lub możesz ją zdefiniować w innej klasie. Zawsze mogliśmy użyć dołączonej właściwości, aby rozszerzyć standardowe kontrolki Microsoft. Ale właściwość zależności, definiujesz ją we własnej kontrolce niestandardowej. np. możesz odziedziczyć kontrolę ze standardowej kontrolki i zdefiniować właściwość zależności we własnej kontrolce i jej używać. Jest to równoważne zdefiniowaniu dołączonej właściwości i użyciu tej dołączonej właściwości w standardowej kontrolce.

spspli
źródło