Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Dit artikel bevat richtlijnen en voorgestelde patronen voor het implementeren van een afhankelijkheidseigenschap die een verzamelingstype is.
Vereiste voorwaarden
In het artikel wordt ervan uitgegaan dat u basiskennis hebt van afhankelijkheidseigenschappen en dat u overzicht van eigenschappen van afhankelijkheden hebt gelezen. Als u de voorbeelden in dit artikel wilt volgen, helpt dit als u bekend bent met Extensible Application Markup Language (XAML) en weet hoe u WPF-toepassingen schrijft.
Een afhankelijkheidseigenschap van het verzamelingstype implementeren
Over het algemeen is het implementatiepatroon voor een afhankelijkheidseigenschap een CLR-eigenschapsomslag die ondersteund wordt door een DependencyProperty-identificator in plaats van een veld of een andere constructie. U kunt hetzelfde patroon volgen wanneer u een afhankelijkheidseigenschap van het verzamelingstype implementeert. Het patroon is complexer als het type verzamelingselement een DependencyObject of een Freezable afgeleide klasse is.
De verzameling initialiseren
Wanneer u een afhankelijkheidseigenschap maakt, geeft u doorgaans de standaardwaarde op via metagegevens van de afhankelijkheidseigenschap in plaats van een initiële eigenschapswaarde op te geven. Als uw eigenschapswaarde echter een verwijzingstype is, moet de standaardwaarde worden ingesteld in de constructor van de klasse die de afhankelijkheidseigenschap registreert. De metagegevens van de afhankelijkheidseigenschap mogen geen standaardwaarde van het verwijzingstype bevatten, omdat deze waarde wordt toegewezen aan alle exemplaren van de klasse, waardoor een singleton-klasse wordt gemaakt.
In het volgende voorbeeld wordt een Aquarium-klasse gedeclareerd die een verzameling van FrameworkElement elementen bevat in een algemene List<T>. De standaardverzamelingswaarde wordt niet via de PropertyMetadata aan de methode RegisterReadOnly(String, Type, Type, PropertyMetadata) doorgegeven. In plaats daarvan wordt de klasseconstructor gebruikt om de standaardverzamelingswaarde in te stellen op een nieuwe algemene List.
public class Aquarium : DependencyObject
{
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata.
private static readonly DependencyPropertyKey s_aquariumContentsPropertyKey =
DependencyProperty.RegisterReadOnly(
name: "AquariumContents",
propertyType: typeof(List<FrameworkElement>),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata()
//typeMetadata: new FrameworkPropertyMetadata(new List<FrameworkElement>())
);
// Set the default collection value in a class constructor.
public Aquarium() => SetValue(s_aquariumContentsPropertyKey, new List<FrameworkElement>());
// Declare a public get accessor.
public List<FrameworkElement> AquariumContents =>
(List<FrameworkElement>)GetValue(s_aquariumContentsPropertyKey.DependencyProperty);
}
public class Fish : FrameworkElement { }
Public Class Aquarium
Inherits DependencyObject
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata.
Private Shared ReadOnly s_aquariumContentsPropertyKey As DependencyPropertyKey =
DependencyProperty.RegisterReadOnly(
name:="AquariumContents",
propertyType:=GetType(List(Of FrameworkElement)),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata())
'typeMetadata:=New FrameworkPropertyMetadata(New List(Of FrameworkElement)))
' Set the default collection value in a class constructor.
Public Sub New()
SetValue(s_aquariumContentsPropertyKey, New List(Of FrameworkElement)())
End Sub
' Declare a public get accessor.
Public ReadOnly Property AquariumContents As List(Of FrameworkElement)
Get
Return CType(GetValue(s_aquariumContentsPropertyKey.DependencyProperty), List(Of FrameworkElement))
End Get
End Property
End Class
Public Class Fish
Inherits FrameworkElement
End Class
Met de volgende testcode worden twee afzonderlijke Aquarium exemplaren geïnstitueert en wordt een ander Fish item aan elke verzameling toegevoegd. Als u de code uitvoert, ziet u dat elk Aquarium object één item in de collectie heeft, zoals verwacht.
private void InitializeAquariums(object sender, RoutedEventArgs e)
{
Aquarium aquarium1 = new();
Aquarium aquarium2 = new();
aquarium1.AquariumContents.Add(new Fish());
aquarium2.AquariumContents.Add(new Fish());
MessageBox.Show(
$"aquarium1 contains {aquarium1.AquariumContents.Count} fish\r\n" +
$"aquarium2 contains {aquarium2.AquariumContents.Count} fish");
}
Private Sub InitializeAquariums(sender As Object, e As RoutedEventArgs)
Dim aquarium1 As New Aquarium()
Dim aquarium2 As New Aquarium()
aquarium1.AquariumContents.Add(New Fish())
aquarium2.AquariumContents.Add(New Fish())
MessageBox.Show($"aquarium1 contains {aquarium1.AquariumContents.Count} fish{Environment.NewLine}" +
$"aquarium2 contains {aquarium2.AquariumContents.Count} fish")
End Sub
Als u echter de klasseconstructor uitcommentarieert en de standaardwaarde van de verzameling doorgeeft als PropertyMetadata aan de methode RegisterReadOnly(String, Type, Type, PropertyMetadata), zult u zien dat elk Aquarium-exemplaar er twee verzamelingsitems krijgt. Dit komt doordat beide Fish exemplaren worden toegevoegd aan dezelfde lijst, die wordt gedeeld door alle exemplaren van de Klasse Aquarium. Dus, wanneer het de bedoeling is dat elk objectexemplaar zijn eigen lijst heeft, moet de standaardwaarde worden ingesteld in de constructor.
Een lees-/schrijfverzameling initialiseren
In het volgende voorbeeld wordt een afhankelijkheidseigenschap voor een lees- en schrijfbaar verzamelingstype in de Aquarium-klasse gedeclareerd, met gebruik van de niet-sleutelhandtekeningmethoden Register(String, Type, Type) en SetValue(DependencyProperty, Object).
public class Aquarium : DependencyObject
{
// Register a dependency property with the specified property name,
// property type, and owner type. Store the dependency property
// identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumContentsProperty =
DependencyProperty.Register(
name: "AquariumContents",
propertyType: typeof(List<FrameworkElement>),
ownerType: typeof(Aquarium)
);
// Set the default collection value in a class constructor.
public Aquarium() => SetValue(AquariumContentsProperty, new List<FrameworkElement>());
// Declare public get and set accessors.
public List<FrameworkElement> AquariumContents
{
get => (List<FrameworkElement>)GetValue(AquariumContentsProperty);
set => SetValue(AquariumContentsProperty, value);
}
}
Public Class Aquarium
Inherits DependencyObject
' Register a dependency property with the specified property name,
' property type, and owner type. Store the dependency property
' identifier as a static member of the class.
Public Shared ReadOnly AquariumContentsProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumContents",
propertyType:=GetType(List(Of FrameworkElement)),
ownerType:=GetType(Aquarium))
' Set the default collection value in a class constructor.
Public Sub New()
SetValue(AquariumContentsProperty, New List(Of FrameworkElement)())
End Sub
' Declare public get and set accessors.
Public Property AquariumContents As List(Of FrameworkElement)
Get
Return CType(GetValue(AquariumContentsProperty), List(Of FrameworkElement))
End Get
Set
SetValue(AquariumContentsProperty, Value)
End Set
End Property
End Class
Afhankelijkheidseigenschappen van FreezableCollection
Een verzamelingstype-afhankelijkheidseigenschap rapporteert niet automatisch wijzigingen in de subeigenschappen. Als u een binding met een verzameling maakt, worden wijzigingen mogelijk niet door de binding weergegeven, waardoor sommige scenario's voor gegevensbinding ongeldig worden. Als u echter FreezableCollection<T> gebruikt voor het type afhankelijkheidseigenschap, worden wijzigingen in de eigenschappen van verzamelingselementen correct gerapporteerd en werkt binding zoals verwacht.
Als u subeigenschapsbinding wilt inschakelen in een verzameling afhankelijkheidsobjecten, gebruikt u het verzamelingstype FreezableCollection, met een typebeperking van een DependencyObject afgeleide klasse.
In het volgende voorbeeld wordt een Aquarium-klasse gedefinieerd die een FreezableCollection bevat met een typebeperking van FrameworkElement. Een standaardverzamelingswaarde is niet opgenomen in de PropertyMetadata die aan de methode RegisterReadOnly(String, Type, Type, PropertyMetadata) wordt doorgegeven. In plaats daarvan wordt de constructor van de klasse gebruikt om de standaardverzamelingswaarde in te stellen op een nieuwe FreezableCollection.
public class Aquarium : DependencyObject
{
// Register a dependency property with the specified property name,
// property type, and owner type.
private static readonly DependencyPropertyKey s_aquariumContentsPropertyKey =
DependencyProperty.RegisterReadOnly(
name: "AquariumContents",
propertyType: typeof(FreezableCollection<FrameworkElement>),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata()
);
// Store the dependency property identifier as a static member of the class.
public static readonly DependencyProperty AquariumContentsProperty =
s_aquariumContentsPropertyKey.DependencyProperty;
// Set the default collection value in a class constructor.
public Aquarium() => SetValue(s_aquariumContentsPropertyKey, new FreezableCollection<FrameworkElement>());
// Declare a public get accessor.
public FreezableCollection<FrameworkElement> AquariumContents =>
(FreezableCollection<FrameworkElement>)GetValue(AquariumContentsProperty);
}
Public Class Aquarium
Inherits DependencyObject
' Register a dependency property with the specified property name,
' property type, and owner type.
Private Shared ReadOnly s_aquariumContentsPropertyKey As DependencyPropertyKey =
DependencyProperty.RegisterReadOnly(
name:="AquariumContents",
propertyType:=GetType(FreezableCollection(Of FrameworkElement)),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata())
' Set the default collection value in a class constructor.
Public Sub New()
SetValue(s_aquariumContentsPropertyKey, New FreezableCollection(Of FrameworkElement)())
End Sub
' Declare a public get accessor.
Public ReadOnly Property AquariumContents As FreezableCollection(Of FrameworkElement)
Get
Return CType(GetValue(s_aquariumContentsPropertyKey.DependencyProperty), FreezableCollection(Of FrameworkElement))
End Get
End Property
End Class
Zie ook
.NET Desktop feedback