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?
źródło
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?
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 DependencyObject
instancjami.
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.
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
});
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 RegisterAttached
parametru metadata jest nazwany defaultMetadata
, a dla Register
niego 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ą PropertyMetadata
tylko z DefaultValue
ustawieniem (z podanych metadanych lub automatycznie). Dopiero kolejne wywołanie OverrideMetadata
faktycznie korzysta z podanych metadanych.
Główna praktyczna różnica polega na tym, że w przypadku zwykłych właściwości, CoerceValueCallback
i PropertyChangedCallback
mają 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 OverrideMetadata
wymaga, 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.).
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:
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.
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.
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.
źródło
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.
źródło
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.
źródło