Abhängigkeitseigenschaften vom Auflistungstyp

Aktualisiert: November 2007

In diesem Thema finden Sie Unterstützung und Mustervorschläge für das Implementieren einer Abhängigkeitseigenschaft, wenn die Eigenschaft zum Auflistungstyp gehört.

Dieses Thema enthält folgende Abschnitte.

  • Implementieren einer Abhängigkeitseigenschaft vom Auflistungstyp
  • Initialisieren der Auflistung mit einem anderem Wert als dem Standardwert
  • Melden von Bindungswertänderungen durch Auflistungseigenschaften
  • Verwandte Abschnitte

Implementieren einer Abhängigkeitseigenschaft vom Auflistungstyp

Für Abhängigkeitseigenschaften wird im Allgemeinen folgendes Implementierungsmuster verwendet: Sie definieren einen CLR-Eigenschaftenwrapper, in dem diese Eigenschaft durch einen DependencyProperty-Bezeichner statt durch ein Feld oder ein anderes Konstrukt unterstützt wird. Dieses Muster gilt auch, wenn Sie eine Eigenschaft vom Auflistungstyp implementieren. Bei einer Eigenschaft vom Auflistungstyp wird dieses Muster jedoch komplexer, wenn der in der Auflistung enthaltene Typ selbst ein DependencyObject oder eine von Freezable abgeleitete Klasse ist.

Initialisieren der Auflistung mit einem anderem Wert als dem Standardwert

Wenn Sie eine Abhängigkeitseigenschaft erstellen, geben Sie den Standardwert der Eigenschaft nicht als anfänglichen Feldwert an. Stattdessen geben Sie den Standardwert über die Metadaten für die Abhängigkeitseigenschaft an. Wenn die Eigenschaft ein Verweistyp ist, so ist der in den Metadaten für die Abhängigkeitseigenschaft angegebene Standardwert kein Standardwert pro Instanz, sondern ein Standardwert, der für alle Instanzen dieses Typs gilt. Daher müssen Sie sorgfältig darauf achten, dass Sie nicht die durch die Metadaten für die Auflistungseigenschaft definierte einzelne statische Auflistung als funktionierenden Standardwert für neu erstellte Instanzen Ihres Typs verwenden. Stattdessen müssen Sie sicherstellen, dass Sie den Auflistungswert bewusst auf eine eindeutige (Instanz-) Auflistung im Rahmen der Klassenkonstruktorlogik festlegen. Andernfalls haben Sie eine unbeabsichtigte Singletonklasse erstellt.

Betrachten Sie das folgende Beispiel. Im nachstehenden Abschnitt des Beispiels wird die Definition für eine Aquarium-Klasse veranschaulicht. Die Klasse definiert die AquariumObjects-Abhängigkeitseigenschaft vom Auflistungstyp, die den generischen List<T>-Typ mit einer FrameworkElement-Typeinschränkung verwendet. Im Register(String, Type, Type, PropertyMetadata)-Aufruf für die Abhängigkeitseigenschaft legen die Metadaten den Standardwert als neue generische List<T> fest.

public class Fish : FrameworkElement { }
public class Aquarium : DependencyObject
{
    private static readonly DependencyPropertyKey AquariumContentsPropertyKey = 
        DependencyProperty.RegisterReadOnly(
          "AquariumContents",
          typeof(List<FrameworkElement>),
          typeof(Aquarium),
          new FrameworkPropertyMetadata(new List<FrameworkElement>())
        );
    public static readonly DependencyProperty AquariumContentsProperty =
        AquariumContentsPropertyKey.DependencyProperty;

    public List<FrameworkElement> AquariumContents
    {
        get { return (List<FrameworkElement>)GetValue(AquariumContentsProperty); }


...


}

Wenn Sie jedoch den Code einfach so wie dargestellt lassen, wird der einzelne Listenstandardwert für alle Instanzen von Aquarium freigegeben. Beim Ausführen des folgenden Testcodes, der zeigen soll, wie Sie zwei separate Aquarium-Instanzen instanziieren und jeder einen einzelnen unterschiedlichen Fish hinzufügen würden, wäre das Ergebnis überraschend:

Aquarium myAq1 = new Aquarium();
Aquarium myAq2 = new Aquarium();
Fish f1 = new Fish();
Fish f2 = new Fish();
myAq1.AquariumContents.Add(f1);
myAq2.AquariumContents.Add(f2);
MessageBox.Show("aq1 contains " + myAq1.AquariumContents.Count.ToString() + " things");
MessageBox.Show("aq2 contains " + myAq2.AquariumContents.Count.ToString() + " things");

Statt über einen Eintrag in jeder Auflistung verfügt jede Auflistung über zwei Einträge! Dies liegt daran, dass jedes Aquarium seinen Fish der Standardwertauflistung hinzugefügt hat, die aus einem einzigen Konstruktoraufruf in den Metadaten resultiert und daher für alle Instanzen freigegeben ist. Diese Situation ist in nahezu keinem Fall erwünscht.

Um dieses Problem zu beheben, müssen Sie für den Abhängigkeitseigenschaftenwert der Auflistung eine eindeutige Instanz im Rahmen der Klassenkonstruktorlogik festlegen. Da diese Eigenschaft eine schreibgeschützte Abhängigkeitseigenschaft ist, verwenden Sie zur Festlegung die SetValue(DependencyPropertyKey, Object)-Methode, mit dem DependencyPropertyKey, der nur innerhalb der Klasse verfügbar ist.

public Aquarium() : base()
{
    SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>()); 
}

Wenn Sie nun denselben Test erneut ausführen würden, entsprächen die Ergebnisse eher Ihren Erwartungen, da jedes Aquarium jetzt seine eigene eindeutige Auflistung unterstützt.

Dieses Muster sieht geringfügig anders aus, wenn Sie sich für eine nicht schreibgeschützte Auflistungseigenschaft entscheiden. In diesem Fall rufen Sie den öffentlichen set-Accessor vom Konstruktor aus auf, um die Initialisierung durchzuführen. Dadurch würde weiterhin die Nicht-Schlüssel-Signatur von SetValue(DependencyProperty, Object) innerhalb Ihres set-Wrappers aufgerufen, mit einem öffentlichen DependencyProperty-Bezeichner.

Melden von Bindungswertänderungen durch Auflistungseigenschaften

Eine Auflistungseigenschaft, die selbst eine Abhängigkeitseigenschaft ist, meldet nicht automatisch Änderungen an ihren untergeordneten Eigenschaften. Wenn Sie Bindungen in einer Auflistung erstellen, kann dies die Bindung daran hindern, Änderungen zu melden, sodass einige Datenbindungsszenarien ungültig gemacht werden. Wenn Sie jedoch den FreezableCollection<T>-Auflistungstyp als Ihren Auflistungstyp verwenden, werden Änderungen an untergeordneten Elementen in der Auflistung ordnungsgemäß gemeldet, und die Bindung funktioniert wie erwartet.

Um die Bindung von untergeordneten Eigenschaften in einem Abhängigkeitsobjekt zu aktivieren, erstellen Sie die Auflistungseigenschaft als FreezableCollection<T>-Typ mit einer Typeinschränkung für diese Auflistung bezüglich jeder vom DependencyObject abgeleiteten Klasse.

Siehe auch

Konzepte

XAML und benutzerdefinierte Klassen

Übersicht über Datenbindung

Übersicht über Abhängigkeitseigenschaften

Benutzerdefinierte Abhängigkeitseigenschaften

Metadaten für Abhängigkeitseigenschaften

Referenz

FreezableCollection<T>