Koleksiyon Türü Bağımlılık Özellikleri

Bu konu başlığında, özelliğin türünün koleksiyon türü olduğu bir bağımlılık özelliğinin nasıl uygulanacağı konusunda rehberlik ve önerilen desenler sağlanır.

Koleksiyon Türü Bağımlılık Özelliği Uygulama

Genel olarak bir bağımlılık özelliği için, izlediğiniz uygulama deseni, bir CLR özellik sarmalayıcısı tanımlamanızdır; burada bu özellik bir alan veya başka bir yapı yerine bir DependencyProperty tanımlayıcı tarafından yedeklenmiştir. Koleksiyon türü özelliği uygularken de aynı deseni izlersiniz. Ancak koleksiyon türü özelliği, koleksiyon içinde yer alan türün kendisi veya Freezable türetilmiş bir DependencyObject sınıf olduğunda desene biraz karmaşıklık ekler.

Koleksiyonu Varsayılan Değerin Ötesinde Başlatma

Bağımlılık özelliği oluşturduğunuzda, özellik varsayılan değerini ilk alan değeri olarak belirtmezsiniz. Bunun yerine, bağımlılık özelliği meta verileri aracılığıyla varsayılan değeri belirtirsiniz. Özelliğiniz bir başvuru türüyse, bağımlılık özelliği meta verilerinde belirtilen varsayılan değer örnek başına varsayılan bir değer değildir; bunun yerine, türün tüm örnekleri için geçerli olan varsayılan bir değerdir. Bu nedenle, koleksiyon özelliği meta verileri tarafından tanımlanan tekil statik koleksiyonu, türünüzün yeni oluşturulan örnekleri için çalışan varsayılan değer olarak kullanmamaya dikkat etmeniz gerekir. Bunun yerine, koleksiyon değerini sınıf oluşturucu mantığınızın bir parçası olarak özellikle benzersiz (örnek) bir koleksiyona ayarladığınızdan emin olmanız gerekir. Aksi takdirde, kasıtsız bir tekil sınıf oluşturmuş olursunuz.

Aşağıdaki örneği inceleyin. Örneğin aşağıdaki bölümünde, varsayılan değere sahip bir kusur içeren bir sınıfın Aquariumtanımı gösterilir. sınıfı, bir tür kısıtlaması ile FrameworkElement genel List<T> türü kullanan koleksiyon türü bağımlılık özelliğini AquariumObjectstanımlar. Register(String, Type, Type, PropertyMetadata) Bağımlılık özelliğinin çağrısında meta veriler varsayılan değeri yeni bir genel List<T>olacak şekilde oluşturur.

Uyarı

Aşağıdaki kod doğru şekilde davranmıyor.

public class Fish : FrameworkElement { }
public class Aquarium : DependencyObject {
    private static readonly DependencyPropertyKey AquariumContentsPropertyKey =
        DependencyProperty.RegisterReadOnly(
          "AquariumContents",
          typeof(List<FrameworkElement>),
          typeof(Aquarium),
          new FrameworkPropertyMetadata(new List<FrameworkElement>())
        );
    public static readonly DependencyProperty AquariumContentsProperty =
        AquariumContentsPropertyKey.DependencyProperty;

    public List<FrameworkElement> AquariumContents
    {
        get { return (List<FrameworkElement>)GetValue(AquariumContentsProperty); }
    }

    // ...
}
Public Class Fish
    Inherits FrameworkElement
End Class
Public Class Aquarium
    Inherits DependencyObject
    Private Shared ReadOnly AquariumContentsPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("AquariumContents", GetType(List(Of FrameworkElement)), GetType(Aquarium), New FrameworkPropertyMetadata(New List(Of FrameworkElement)()))
    Public Shared ReadOnly AquariumContentsProperty As DependencyProperty = AquariumContentsPropertyKey.DependencyProperty

    Public ReadOnly Property AquariumContents() As List(Of FrameworkElement)
        Get
            Return CType(GetValue(AquariumContentsProperty), List(Of FrameworkElement))
        End Get
    End Property

    ' ...

End Class

Ancak, kodu gösterildiği gibi bıraktıysanız, bu tek liste varsayılan değeri tüm örnekleri Aquariumiçin paylaşılır. İki ayrı Aquarium örneğin örneğini nasıl oluşturabileceğinizi ve her birine tek bir farklı Fish örneği nasıl ekleyebileceğinizi gösteren aşağıdaki test kodunu çalıştırdıysanız, şaşırtıcı bir sonuç görürsünüz:

Aquarium myAq1 = new Aquarium();
Aquarium myAq2 = new Aquarium();
Fish f1 = new Fish();
Fish f2 = new Fish();
myAq1.AquariumContents.Add(f1);
myAq2.AquariumContents.Add(f2);
MessageBox.Show("aq1 contains " + myAq1.AquariumContents.Count.ToString() + " things");
MessageBox.Show("aq2 contains " + myAq2.AquariumContents.Count.ToString() + " things");
Dim myAq1 As New Aquarium()
Dim myAq2 As New Aquarium()
Dim f1 As New Fish()
Dim f2 As New Fish()
myAq1.AquariumContents.Add(f1)
myAq2.AquariumContents.Add(f2)
MessageBox.Show("aq1 contains " & myAq1.AquariumContents.Count.ToString() & " things")
MessageBox.Show("aq2 contains " & myAq2.AquariumContents.Count.ToString() & " things")

Her koleksiyonun bir sayısı yerine, her koleksiyonun iki sayısı vardır! Bunun nedeni, her Aquarium birinin varsayılan değer koleksiyonuna Fish eklenmesidir. Bu, meta verilerdeki tek bir oluşturucu çağrısından kaynaklanır ve bu nedenle tüm örnekler arasında paylaşılır. Bu durum neredeyse hiç istediğiniz gibi değil.

Bu sorunu düzeltmek için koleksiyon bağımlılığı özellik değerini sınıf oluşturucu çağrısının bir parçası olarak benzersiz bir örneğe sıfırlamanız gerekir. özelliği salt okunur bir bağımlılık özelliği olduğundan, yalnızca sınıfı içinde erişilebilir olan öğesini kullanarak DependencyPropertyKey bunu ayarlamak için yöntemini kullanırsınızSetValue(DependencyPropertyKey, Object).

public Aquarium() : base()
{
    SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>());
}
Public Sub New()
    MyBase.New()
    SetValue(AquariumContentsPropertyKey, New List(Of FrameworkElement)())
End Sub

Şimdi, aynı test kodunu yeniden çalıştırdıysanız, her Aquarium birinin kendi benzersiz koleksiyonunu desteklediği daha fazla beklenen sonuç görebilirsiniz.

Koleksiyon özelliğinizin okuma-yazma olmasını seçerseniz bu düzende küçük bir çeşitleme olacaktır. Bu durumda, başlatmayı yapmak için oluşturucudan ortak küme erişimcisini çağırabilirsiniz. Bu, ortak tanımlayıcı DependencyProperty kullanarak küme sarmalayıcınızın içindeki anahtar olmayan imzasını SetValue(DependencyProperty, Object) çağırmaya devam eder.

Koleksiyon Özelliklerinden Bağlama Değeri Değişikliklerini Raporlama

Kendisi bağımlılık özelliği olan bir koleksiyon özelliği, değişiklikleri otomatik olarak alt özelliklerine raporlamaz. Bir koleksiyonda bağlamalar oluşturuyorsanız bu, bağlamanın değişiklikleri raporlamasını önleyerek bazı veri bağlama senaryolarını geçersiz kılar. Ancak koleksiyon türünü koleksiyon türünüz FreezableCollection<T> olarak kullanırsanız, koleksiyondaki kapsanan öğelere yapılan alt özellik değişiklikleri düzgün şekilde bildirilir ve bağlama beklendiği gibi çalışır.

Bağımlılık nesnesi koleksiyonunda alt özellik bağlamasını etkinleştirmek için, koleksiyon özelliğini tür FreezableCollection<T>olarak oluşturun ve bu koleksiyon için türetilmiş herhangi DependencyObject bir sınıfa yönelik bir tür kısıtlaması oluşturun.

Ayrıca bkz.