Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln innehåller vägledning och föreslagna mönster för att implementera en beroendeegenskap som är en samlingstyp.
Förutsättningar
Artikeln förutsätter grundläggande kunskaper om beroendeegenskaper och att du har läst Översikt över beroendeegenskaper. Om du vill följa exemplen i den här artikeln hjälper det om du är bekant med XAML (Extensible Application Markup Language) och vet hur du skriver WPF-program.
Implementera en beroendeegenskap av samlingstyp
I allmänhet är implementeringsmönstret för en beroendeegenskap en CLR-egenskapsomslutning som backas upp av en DependencyProperty identifierare i stället för ett fält eller en annan konstruktion. Du kan följa samma mönster när du implementerar en beroendeegenskap av samlingstyp. Mönstret är mer komplext om samlingselementtypen är en DependencyObject eller en Freezable härledd klass.
Initiera samlingen
När du skapar en beroendeegenskap anger du vanligtvis standardvärdet via metadata för beroendeegenskap i stället för att ange ett initialt egenskapsvärde. Men om egenskapsvärdet är en referenstyp bör standardvärdet anges i konstruktorn för klassen som registrerar beroendeegenskapen. Metadata för beroendeegenskap bör inte innehålla ett standardvärde av referenstyp eftersom det värdet tilldelas till alla instanser av klassen, vilket skapar en singleton-klass.
I följande exempel deklareras en Aquarium klass som innehåller en samling FrameworkElement element i en allmän List<T>. Ett standardsamlingsvärde ingår inte i den PropertyMetadata som skickas till RegisterReadOnly(String, Type, Type, PropertyMetadata) metoden, och i stället används klasskonstruktorn för att ange standardsamlingsvärdet till en ny allmän 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
Följande testkod instansierar två separata Aquarium instanser och lägger till ett annat Fish objekt i varje samling. Om du kör koden ser du att varje Aquarium instans har ett enda samlingsobjekt som förväntat.
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
Men om du kommenterar ut klasskonstruktorn och skickar standardsamlingsvärdet PropertyMetadata till RegisterReadOnly(String, Type, Type, PropertyMetadata) metoden ser du att varje Aquarium instans hämtar två samlingsobjekt! Det beror på att båda Fish instanserna läggs till i samma lista, som delas av alla instanser av klassen Aquarium. Så när avsikten är att varje objektinstans ska ha en egen lista bör standardvärdet anges i klasskonstruktorn.
Initiera en skriv-läsa samling
I följande exempel deklareras en samlingsberoendeegenskap av typen läs-skriv i klassen Aquarium med de icke-nyckelsignaturmetoderna Register(String, Type, Type) och 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
FreezableCollection-beroendeegenskaper
En beroendeegenskap av samlingstyp rapporterar inte automatiskt ändringar i dess underegenskaper. Om du binder till en samling kanske bindningen inte rapporterar ändringar, vilket gör vissa databindningsscenarier ogiltiga. Men om du använder FreezableCollection<T> för beroendeegenskapstypen rapporteras ändringar av egenskaperna för samlingselement korrekt och bindningen fungerar som förväntat.
Om du vill aktivera underproperty-bindning i en samling beroendeobjekt använder du samlingstypen FreezableCollection, med en typbegränsning för alla DependencyObject härledda klasser.
I följande exempel deklareras en Aquarium klass som innehåller en FreezableCollection med en typbegränsning av FrameworkElement. Ett standardinsamlingsvärde ingår inte i den PropertyMetadata som skickas till RegisterReadOnly(String, Type, Type, PropertyMetadata) metoden, och i stället används klasskonstruktorn för att ange standardsamlingsvärdet till en ny 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
Se även
.NET Desktop feedback