Properti dependensi jenis koleksi (WPF .NET)
Artikel ini menyediakan panduan dan pola yang disarankan untuk menerapkan properti dependensi yang merupakan jenis koleksi.
Prasyarat
Artikel ini mengasumsikan pengetahuan dasar tentang properti dependensi, dan bahwa Anda telah membaca gambaran umum properti Dependensi. Untuk mengikuti contoh dalam artikel ini, ini membantu jika Anda terbiasa dengan Extensible Application Markup Language (XAML) dan tahu cara menulis aplikasi WPF.
Menerapkan properti dependensi jenis koleksi
Secara umum, pola implementasi untuk properti dependensi adalah pembungkus properti CLR yang DependencyProperty didukung oleh pengidentifikasi alih-alih bidang atau konstruksi lainnya. Anda dapat mengikuti pola yang sama saat menerapkan properti dependensi jenis koleksi. Polanya lebih kompleks jika jenis elemen koleksi adalah DependencyObject kelas turunan atau Freezable .
Menginisialisasi koleksi
Saat membuat properti dependensi, Anda biasanya menentukan nilai default melalui metadata properti dependensi alih-alih menentukan nilai properti awal. Namun, jika nilai properti Anda adalah jenis referensi, nilai default harus diatur dalam konstruktor kelas yang mendaftarkan properti dependensi. Metadata properti dependensi tidak boleh menyertakan nilai jenis referensi default karena nilai tersebut akan ditetapkan ke semua instans kelas, membuat kelas singleton.
Contoh berikut mendeklarasikan Aquarium
kelas yang berisi kumpulan FrameworkElement elemen dalam generik List<T>. Nilai koleksi default tidak disertakan dalam yang diteruskan PropertyMetadata ke RegisterReadOnly(String, Type, Type, PropertyMetadata) metode , dan sebaliknya konstruktor kelas digunakan untuk mengatur nilai koleksi default ke generik List
baru .
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
Kode pengujian berikut membuat instans terpisah Aquarium
dan menambahkan item yang berbeda Fish
ke setiap koleksi. Jika Anda menjalankan kode, Anda akan melihat bahwa setiap Aquarium
instans memiliki satu item koleksi, seperti yang diharapkan.
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
Tetapi, jika Anda mengomentari konstruktor kelas dan meneruskan nilai koleksi default ke PropertyMetadata RegisterReadOnly(String, Type, Type, PropertyMetadata) metode , Anda akan melihat bahwa setiap Aquarium
instans mendapatkan dua item koleksi! Ini karena kedua Fish
instans ditambahkan ke daftar yang sama, yang dibagikan oleh semua instans kelas Akuarium. Jadi, ketika niatnya adalah agar setiap instans objek memiliki daftarnya sendiri, nilai default harus diatur dalam konstruktor kelas.
Menginisialisasi koleksi baca-tulis
Contoh berikut mendeklarasikan properti dependensi jenis koleksi baca-tulis di Aquarium
kelas , menggunakan metode Register(String, Type, Type) tanda tangan non-kunci dan 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
Properti dependensi FreezableCollection
Properti dependensi jenis koleksi tidak secara otomatis melaporkan perubahan dalam subpropertinya. Akibatnya, jika Anda mengikat ke koleksi, pengikatan mungkin tidak melaporkan perubahan, membatalkan beberapa skenario pengikatan data. Tetapi, jika Anda menggunakan FreezableCollection<T> untuk jenis properti dependensi, perubahan pada properti elemen koleksi dilaporkan dengan benar dan pengikatan berfungsi seperti yang diharapkan.
Untuk mengaktifkan pengikatan subproperti dalam kumpulan objek dependensi, gunakan jenis FreezableCollection
koleksi , dengan batasan jenis kelas turunan apa pun DependencyObject .
Contoh berikut mendeklarasikan Aquarium
kelas yang berisi FreezableCollection
dengan batasan FrameworkElementjenis . Nilai koleksi default tidak disertakan dalam yang diteruskan PropertyMetadata ke RegisterReadOnly(String, Type, Type, PropertyMetadata) metode , dan sebaliknya konstruktor kelas digunakan untuk mengatur nilai koleksi default ke yang baru 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
Lihat juga
.NET Desktop feedback
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk