Właściwości zależności typu kolekcji (WPF .NET)
Ten artykuł zawiera wskazówki i sugerowane wzorce implementowania właściwości zależności, która jest typem kolekcji.
Ważne
Dokumentacja przewodnika dla komputerów dla platform .NET 7 i .NET 6 jest w budowie.
Wymagania wstępne
W tym artykule przyjęto założenie, że masz podstawową wiedzę na temat właściwości zależności i zapoznasz się z omówieniem właściwości zależności. Aby postępować zgodnie z przykładami w tym artykule, warto zapoznać się z językiem Extensible Application Markup Language (XAML) i wiedzieć, jak pisać aplikacje WPF.
Implementowanie właściwości zależności typu kolekcji
Ogólnie rzecz biorąc, wzorzec implementacji dla właściwości zależności to otoka właściwości CLR wspierana przez DependencyProperty identyfikator zamiast pola lub innej konstrukcji. Możesz postępować zgodnie z tym samym wzorcem podczas implementowania właściwości zależności typu kolekcji. Wzorzec jest bardziej złożony, jeśli typ elementu kolekcji to DependencyObject lub klasa pochodna Freezable .
Inicjowanie kolekcji
Podczas tworzenia właściwości zależności zazwyczaj określasz wartość domyślną za pomocą metadanych właściwości zależności zamiast określania początkowej wartości właściwości. Jeśli jednak wartość właściwości jest typem odwołania, wartość domyślna powinna zostać ustawiona w konstruktorze klasy, która rejestruje właściwość zależności. Metadane właściwości zależności nie powinny zawierać domyślnej wartości typu odwołania, ponieważ ta wartość zostanie przypisana do wszystkich wystąpień klasy, tworząc pojedynczą klasę.
Poniższy przykład deklaruje klasę Aquarium
zawierającą kolekcję FrameworkElement elementów w klasie ogólnej List<T>. Domyślna wartość kolekcji nie jest uwzględniona w przekazanej PropertyMetadataRegisterReadOnly(String, Type, Type, PropertyMetadata) metodzie, a zamiast tego konstruktor klasy służy do ustawiania domyślnej wartości kolekcji na nową ogólną List
wartość .
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
Poniższy kod testowy tworzy wystąpienie dwóch oddzielnych Aquarium
wystąpień i dodaje inny Fish
element do każdej kolekcji. Jeśli uruchomisz kod, zobaczysz, że każde Aquarium
wystąpienie ma jeden element kolekcji zgodnie z oczekiwaniami.
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
Jeśli jednak oznaczysz jako komentarz konstruktor klasy i przekażesz domyślną wartość kolekcji jako PropertyMetadata metodę RegisterReadOnly(String, Type, Type, PropertyMetadata) , zobaczysz, że każde Aquarium
wystąpienie pobiera dwa elementy kolekcji. Dzieje się tak, ponieważ oba Fish
wystąpienia są dodawane do tej samej listy, która jest współdzielona przez wszystkie wystąpienia klasy Aquarium. Dlatego, gdy intencja jest dla każdego wystąpienia obiektu, aby mieć własną listę, wartość domyślna powinna być ustawiona w konstruktorze klasy.
Inicjowanie kolekcji odczytu i zapisu
Poniższy przykład deklaruje właściwość zależności typu kolekcji do odczytu i zapisu w Aquarium
klasie przy użyciu metod Register(String, Type, Type) sygnatur innych niż klucz i 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
Właściwości zależności FreezableCollection
Właściwość zależności typu kolekcji nie zgłasza automatycznie zmian w jej właściwościach podrzędnych. W związku z tym, jeśli wiążesz się z kolekcją, powiązanie może nie zgłaszać zmian, unieważniając niektóre scenariusze powiązania danych. Jeśli jednak używasz FreezableCollection<T> dla typu właściwości zależności, zmiany właściwości elementów kolekcji są prawidłowo zgłaszane, a powiązanie działa zgodnie z oczekiwaniami.
Aby włączyć powiązanie podwłaściwości w kolekcji obiektów zależności, użyj typu kolekcji , z ograniczeniem typu FreezableCollection
dowolnej DependencyObject klasy pochodnej.
Poniższy przykład deklaruje klasę Aquarium
zawierającą FreezableCollection
ograniczenie FrameworkElementtypu . Domyślna wartość kolekcji nie jest uwzględniona w przekazanej PropertyMetadata metodzie RegisterReadOnly(String, Type, Type, PropertyMetadata) , a zamiast tego konstruktor klasy jest używany do ustawiania domyślnej wartości kolekcji na nową 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
Zobacz też
.NET Desktop feedback
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla