Was ist der Unterschied zwischen einer (benutzerdefinierten) Abhängigkeitseigenschaft und einer angehängten Eigenschaft in WPF? Was sind die Verwendungszwecke für jeden? Wie unterscheiden sich die Implementierungen normalerweise?
quelle
Was ist der Unterschied zwischen einer (benutzerdefinierten) Abhängigkeitseigenschaft und einer angehängten Eigenschaft in WPF? Was sind die Verwendungszwecke für jeden? Wie unterscheiden sich die Implementierungen normalerweise?
Da ich wenig bis gar keine Dokumentation zu diesem Thema gefunden habe, musste ich mich im Quellcode umsehen , aber hier ist eine Antwort.
Es gibt einen Unterschied zwischen der Registrierung einer Abhängigkeitseigenschaft als reguläre und als angehängte Eigenschaft, die keine "philosophische" ist ( reguläre Eigenschaften sollen vom deklarierenden Typ verwendet werden, und seine abgeleiteten Typen, angehängte Eigenschaften sollen als verwendet werden Erweiterungen für beliebige DependencyObject
Instanzen ). "Philosophisch", da, wie @MarqueIV in seinem Kommentar zu @ ReedCopseys Antwort feststellte, reguläre Eigenschaften auch mit beliebigen DependencyObject
Instanzen verwendet werden können.
Darüber hinaus muss ich anderen Antworten widersprechen, die besagen, dass die angehängte Eigenschaft "Typ der Abhängigkeitseigenschaft" ist, weil sie irreführend ist - es gibt keine "Arten" von Abhängigkeitseigenschaften. Dem Framework ist es egal, ob die Eigenschaft als angehängt registriert wurde oder nicht - es ist nicht einmal möglich zu bestimmen (in dem Sinne, dass diese Informationen nicht aufgezeichnet werden, weil sie irrelevant sind). Tatsächlich werden alle Eigenschaften so registriert, als wären sie angehängte Eigenschaften, aber bei regulären Eigenschaften werden einige zusätzliche Dinge getan, die ihr Verhalten geringfügig ändern.
Um Ihnen die Mühe zu ersparen, den Quellcode selbst durchzugehen, finden Sie hier eine überarbeitete Version dessen, was passiert.
Wenn Sie eine Eigenschaft ohne angegebene Metadaten registrieren, rufen Sie auf
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
liefert genau das gleiche Ergebnis wie beim Aufruf
DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
Wenn Sie jedoch Metadaten angeben, rufen Sie auf
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
ist gleichbedeutend mit anrufen
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
});
Der Hauptunterschied (und der einzige) zwischen regulären und angehängten Abhängigkeitseigenschaften sind die Standardmetadaten, die über die DependencyProperty.DefaultMetadata- Eigenschaft verfügbar sind . Dies wird sogar im Abschnitt Bemerkungen erwähnt :
Bei nicht angehängten Eigenschaften kann der von dieser Eigenschaft zurückgegebene Metadatentyp nicht in abgeleitete Typen des PropertyMetadata- Typs umgewandelt werden, selbst wenn die Eigenschaft ursprünglich mit einem abgeleiteten Metadatentyp registriert wurde. Wenn Sie die ursprünglich registrierten Metadaten einschließlich des möglicherweise abgeleiteten ursprünglichen Metadatentyps möchten, rufen Sie stattdessen GetMetadata (Typ) auf und übergeben Sie den ursprünglichen Registrierungstyp als Parameter.
Bei angehängten Eigenschaften stimmt der Typ der von dieser Eigenschaft zurückgegebenen Metadaten mit dem Typ überein, der in der ursprünglichen Registrierungsmethode RegisterAttached angegeben wurde .
Dies ist im bereitgestellten Code deutlich sichtbar. In den Registrierungsmethoden sind auch kleine Hinweise verborgen, dh RegisterAttached
der Metadatenparameter wird benannt defaultMetadata
, während Register
er benannt wird typeMetadata
. Für angehängte Eigenschaften werden die bereitgestellten Metadaten zu Standardmetadaten. Bei regulären Eigenschaften sind die Standardmetadaten jedoch immer eine neue Instanz von PropertyMetadata
nur DefaultValue
gesetzt (entweder aus bereitgestellten Metadaten oder automatisch). Nur der nachfolgende Aufruf OverrideMetadata
verwendet tatsächlich die bereitgestellten Metadaten.
Der wichtigste praktische Unterschied ist , dass bei regelmäßigen Eigenschaften der CoerceValueCallback
und PropertyChangedCallback
anwendbar sind nur vom Typ der als Eigentümer Typ deklarierte abgeleiteten Typen und für angefügten Eigenschaften , sie sind anwendbar für alle Arten. ZB in diesem Szenario:
var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");
Das registrierte Objekt PropertyChangedCallback
wird aufgerufen, wenn das Objekt als angeschlossenes Objekt registriert wurde. Es wird jedoch nicht aufgerufen, wenn es als reguläres Objekt registriert wurde. Gleiches gilt für CoerceValueCallback
.
Ein sekundärer Unterschied ergibt sich aus der Tatsache, OverrideMetadata
dass der gelieferte Typ von abgeleitet werden muss DependencyObject
. In der Praxis bedeutet dies , dass der Eigentümer Typ für regelmäßige Eigenschaften ableiten muß aus DependencyObject
, während für angebrachte Eigenschaften in sein kann jede Art (einschließlich statischen Klassen, Strukturen, Aufzählungen, Delegierten, etc.).
Neben dem Vorschlag von @ MarqueIV bin ich mehrmals auf die Meinung gestoßen, dass reguläre und angehängte Eigenschaften sich in der Art und Weise unterscheiden, wie sie in XAML verwendet werden können . Diese regulären Eigenschaften erfordern nämlich eine implizite Namenssyntax im Gegensatz zu einer expliziten Namenssyntax, die für angehängte Eigenschaften erforderlich ist. Dies ist technisch nicht wahr , obwohl dies in der Praxis normalerweise der Fall ist. Zur Klarheit:
<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" />
<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />
In reinem XAML gelten für die Verwendung dieser Syntaxen nur die folgenden Regeln:
Wenn Sie diese Bedingungen erfüllen, können Sie die entsprechende Syntax verwenden, unabhängig davon, ob die Eigenschaft für die Sicherungsabhängigkeit als regulär oder angehängt registriert wurde.
Das erwähnte Missverständnis wird nun durch die Tatsache verursacht, dass die überwiegende Mehrheit der Tutorials (zusammen mit Standard- Visual Studio- Codefragmenten) Sie anweist, die CLR- Eigenschaft für reguläre Abhängigkeitseigenschaften zu verwenden und Accessoren für angehängte abzurufen / festzulegen. Aber nichts hindert Sie daran, beide gleichzeitig zu verwenden, sodass Sie die von Ihnen bevorzugte Syntax verwenden können.
Angehängte Eigenschaften sind eine Art Abhängigkeitseigenschaft. Der Unterschied besteht darin, wie sie verwendet werden.
Bei einer angehängten Eigenschaft wird die Eigenschaft für eine Klasse definiert, die nicht dieselbe Klasse ist, für die sie verwendet wird. Dies wird normalerweise für das Layout verwendet. Gute Beispiele sind Panel.ZIndex oder Grid.Row - Sie wenden dies auf ein Steuerelement an (dh: Button), aber es ist tatsächlich in Panel oder Grid definiert. Die Eigenschaft ist an die Instanz der Schaltfläche "angehängt".
Auf diese Weise kann ein Container beispielsweise Eigenschaften erstellen, die für jedes UI-Element verwendet werden können.
Bei den Implementierungsunterschieden geht es im Grunde nur darum, Register vs. RegisterAttached zu verwenden, wenn Sie die Eigenschaft definieren.
Angehängte Eigenschaften sind im Wesentlichen für die Containerelemente gedacht. Wenn Sie beispielsweise ein Raster und ein Raster haben, wird dies jetzt als angehängte Eigenschaft eines Rasterelements betrachtet. Sie können diese Eigenschaft auch in Texbox, Schaltfläche usw. verwenden, um dessen festzulegen in das Raster legen.
Die Abhängigkeitseigenschaft ist wie die Eigenschaft, die im Grunde zu einer anderen Klasse gehört und in einer anderen Klasse verwendet wird. Beispiel: Wie Sie hier ein Rechteck haben, sind Höhe und Breite reguläre Eigenschaften des Rechtecks, aber links und oben sind die Abhängigkeitseigenschaften, da sie zur Canvass-Klasse gehören.
quelle
Angehängte Eigenschaften sind eine spezielle Art von DependencyProperties. Mit ihnen können Sie einem Objekt einen Wert hinzufügen, der nichts über diesen Wert weiß. Ein gutes Beispiel für dieses Konzept sind Layout-Panels. Jedes Layoutfenster benötigt unterschiedliche Daten, um seine untergeordneten Elemente auszurichten. Der Canvas benötigt oben und links, das DockPanel benötigt Dock usw. Da Sie Ihr eigenes Layout-Panel schreiben können, ist die Liste unendlich. Sie sehen, es ist nicht möglich, alle diese Eigenschaften in allen WPF-Steuerelementen zu haben. Die Lösung sind Eigenschaften beigefügt. Sie werden durch das Steuerelement definiert, das die Daten eines anderen Steuerelements in einem bestimmten Kontext benötigt. Zum Beispiel ein Element, das von einem übergeordneten Layoutfenster ausgerichtet wird.
quelle
Ich denke, Sie können angehängte Eigenschaften in der Klasse selbst oder in einer anderen Klasse definieren. Wir könnten immer angehängte Eigenschaften verwenden, um Standard-Microsoft-Steuerelemente zu erweitern. Aber die Abhängigkeitseigenschaft definieren Sie in Ihrem eigenen benutzerdefinierten Steuerelement. Beispiel: Sie können Ihr Steuerelement von einem Standardsteuerelement erben und eine Abhängigkeitseigenschaft in Ihrem eigenen Steuerelement definieren und verwenden. Dies entspricht dem Definieren einer angehängten Eigenschaft und dem Verwenden dieser angehängten Eigenschaft im Standardsteuerelement.
quelle