Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek obsahuje pokyny a navrhované vzory pro implementaci vlastnosti závislosti, která je typem kolekce.
Požadavky
Článek předpokládá základní znalost vlastností závislostí a že jste si přečetli přehled vlastností závislostí. Pokud chcete postupovat podle příkladů v tomto článku, pomůže vám to, pokud znáte jazyk XAML (Extensible Application Markup Language) a víte, jak psát aplikace WPF.
Implementujte vlastnost závislosti typu kolekce
Obecně platí, že model implementace vlastnosti závislosti je obálka vlastností CLR zálohovaná identifikátorem DependencyProperty namísto pole nebo jiného konstruktoru. Při implementaci vlastnosti závislosti typu kolekce můžete postupovat stejným způsobem. Model je složitější, pokud typ elementu kolekce je DependencyObject nebo Freezable odvozené třídy.
Inicializujte kolekci
Při vytváření vlastnosti závislosti obvykle zadáte výchozí hodnotu prostřednictvím metadat vlastností závislostí místo zadání počáteční hodnoty vlastnosti. Pokud je však hodnota vlastnosti referenční typ, měla by být výchozí hodnota nastavena v konstruktoru třídy, která registruje vlastnost závislosti. Metadata vlastnosti závislosti by neměla obsahovat výchozí hodnotu referenčního typu, protože tato hodnota bude přiřazena ke všem instancím třídy, čímž se vytvoří jediná instance třídy.
Následující příklad deklaruje třídu Aquarium, která obsahuje kolekci FrameworkElement elementů v obecné List<T>. Výchozí hodnota kolekce není zahrnuta v PropertyMetadata předaném metodě RegisterReadOnly(String, Type, Type, PropertyMetadata), a místo toho konstruktor třídy nastavuje výchozí hodnotu kolekce na nový obecný 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
Následující testovací kód vytvoří dvě samostatné instance Aquarium a přidá do každé kolekce odlišnou položku Fish. Pokud kód spustíte, uvidíte, že každá instance Aquarium má jednu položku kolekce podle očekávání.
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
Pokud ale zakomentujete konstruktor třídy a předáte výchozí hodnotu kolekce jako PropertyMetadata metodě RegisterReadOnly(String, Type, Type, PropertyMetadata), uvidíte, že každá instance Aquarium získá dvě položky kolekce! Je to proto, že oba Fish instance jsou přidány do stejného seznamu, který je sdílen všemi instancemi třídy Aquarium. Takže pokud je záměr pro každou instanci objektu, aby měla svůj vlastní seznam, měla by být výchozí hodnota nastavena v konstruktoru třídy.
Inicializujte kolekci pro čtení i zápis
Následující příklad deklaruje vlastnost závislostí typu kolekce pro čtení i zápis ve třídě Aquarium pomocí metod podpisu bez klíče Register(String, Type, Type) a 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 – vlastnosti závislosti
Vlastnost závislosti typu kolekce automaticky nehlásí změny ve svých dílčích vlastnostech. V důsledku toho, pokud se vážete na kolekci, vazba nemusí hlásit změny, čímž se zneplatní některé scénáře datových vazeb. Pokud však použijete FreezableCollection<T> pro typ vlastnosti závislosti, změny vlastností prvků kolekce jsou správně hlášeny a vazba funguje podle očekávání.
Chcete-li povolit vazbu na "subproperty" v kolekci závislostních objektů, použijte typ kolekce FreezableCollections omezením typu na jakoukoli třídu odvozenou z DependencyObject.
Následující příklad deklaruje třídu Aquarium, která obsahuje FreezableCollection s omezením typu FrameworkElement. Do PropertyMetadata předané metodě RegisterReadOnly(String, Type, Type, PropertyMetadata) není zahrnuta výchozí hodnota kolekce a místo toho se konstruktor třídy používá k nastavení výchozí hodnoty kolekce na novou 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
Viz také
- FreezableCollection<T>
- XAML a vlastní třídy pro WPF
- Přehled datových vazeb
- Přehled vlastností závislosti
- Vlastní vlastnosti závislosti
- Metadatová vlastnost závislosti
.NET Desktop feedback