この記事では、コレクション型の依存関係プロパティを実装するためのガイダンスと推奨パターンについて説明します。
[前提条件]
この記事では、依存関係プロパティの基本的な知識と、依存関係プロパティの概要
コレクション型の依存関係プロパティを実装する
一般に、依存関係プロパティの実装パターンは、フィールドやその他のコンストラクトではなく、DependencyProperty 識別子によってサポートされる CLR プロパティ ラッパーです。 コレクション型の依存関係プロパティを実装する場合も、同じパターンに従うことができます。 コレクション要素の型が DependencyObject または Freezable 派生クラスである場合、パターンはより複雑になります。
コレクションを初期化する
依存関係プロパティを作成するときは、通常、初期プロパティ値を指定する代わりに、依存関係プロパティメタデータを使用して既定値を指定します。 ただし、プロパティ値が参照型の場合は、依存関係プロパティを登録するクラスのコンストラクターで既定値を設定する必要があります。 依存関係プロパティのメタデータには、その値がクラスのすべてのインスタンスに割り当てられ、シングルトン クラスが作成されるため、既定の参照型の値を含めることはできません。
次の例では、ジェネリック Aquarium
内の FrameworkElement 要素のコレクションを含む List<T> クラスを宣言します。 既定のコレクション値は、PropertyMetadata メソッドに渡される RegisterReadOnly(String, Type, Type, PropertyMetadata) には含まれません。代わりに、クラス コンストラクターを使用して、既定のコレクション値を新しいジェネリック 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
次のテスト コードでは、2 つの個別の Aquarium
インスタンスをインスタンス化し、各コレクションに異なる Fish
項目を追加します。 コードを実行すると、各 Aquarium
インスタンスに期待どおりに 1 つのコレクション項目があることがわかります。
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
ただし、クラス コンストラクターをコメント アウトし、既定のコレクション値を PropertyMetadata メソッドに RegisterReadOnly(String, Type, Type, PropertyMetadata) 渡すと、各 Aquarium
インスタンスで 2 つのコレクション項目が取得されることがわかります。 これは、両方の Fish
インスタンスが同じリストに追加されるためです。これは、Aquarium クラスのすべてのインスタンスによって共有されます。 そのため、意図がオブジェクト インスタンスごとに独自のリストを持つ場合は、クラス コンストラクターで既定値を設定する必要があります。
読み取り/書き込みコレクションを初期化する
次の例では、キー以外のシグネチャ メソッド Aquarium
と Register(String, Type, Type)を使用して、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 依存関係プロパティ
コレクション型の依存関係プロパティは、サブプロパティの変更を自動的に報告しません。 その結果、コレクションにバインドする場合、バインディングによって変更が報告されず、一部のデータ バインディング シナリオが無効になる可能性があります。 ただし、依存関係プロパティの型に FreezableCollection<T> を使用すると、コレクション要素のプロパティへの変更が適切に報告され、バインドが期待どおりに動作します。
依存関係オブジェクトのコレクションでサブプロパティ バインディングを有効にするには、コレクション型 FreezableCollection
を使用し、任意の DependencyObject 派生クラスの型制約を指定します。
次の例では、Aquarium
の型制約を持つ FreezableCollection
を含む FrameworkElement クラスを宣言します。 既定のコレクション値は、PropertyMetadata メソッドに渡される RegisterReadOnly(String, Type, Type, PropertyMetadata) には含まれません。代わりに、クラス コンストラクターを使用して、既定のコレクション値を新しい 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
こちらも参照ください
- FreezableCollection<T>
- WPF 用の XAML クラスとカスタム クラス
- データ バインディングの概要
- 依存関係プロパティの概要
- カスタム依存関係プロパティ
- 依存関係プロパティメタデータ
.NET Desktop feedback