Proprietà di dipendenza di tipo insieme
Aggiornamento: novembre 2007
In questo argomento vengono fornite linee guida e suggeriti modelli per l'implementazione di una proprietà di dipendenza in cui la proprietà è di tipo insieme.
Nel presente argomento sono contenute le seguenti sezioni.
- Implementazione di una proprietà di dipendenza di tipo insieme
- Inizializzazione dell'insieme oltre il valore predefinito
- Creazione di report relativi alle modifiche dei valori di associazione nelle proprietà dell'insieme
- Argomenti correlati
Implementazione di una proprietà di dipendenza di tipo insieme
Per una proprietà di dipendenza generica, il modello di implementazione seguito consiste nel definire un wrapper della proprietà CLR, nel quale quella proprietà è supportata da un identificatore DependencyProperty, anziché da un campo o da un altro costrutto. Questo stesso modello viene seguito quando si implementa una proprietà di tipo insieme. Tuttavia, una proprietà di tipo insieme aggiunge alcuni aspetti più complessi al modello, se il tipo contenuto all'interno dell'insieme è esso stesso un oggetto DependencyObject o una classe derivata Freezable.
Inizializzazione dell'insieme oltre il valore predefinito
Quando si crea una proprietà di dipendenza, non si specifica il valore predefinito della proprietà come valore iniziale del campo. Al contrario, viene specificato il valore predefinito tramite i metadati della proprietà di dipendenza. Se la proprietà è un tipo di riferimento, il valore predefinito specificato nei metadati della proprietà di dipendenza non è un valore predefinito per istanza, bensì un valore predefinito che viene applicato a tutte le istanze del tipo. Pertanto, è necessario prestare attenzione a non utilizzare il singolo insieme statico definito dai metadati della proprietà dell'insieme come valore di lavoro predefinito per le istanze del tipo appena create. È necessario assicurarsi invece di impostare deliberatamente il valore dell'insieme su un unico insieme (istanza), come parte della logica del costruttore di classi. In caso contrario, sarà stata creata una classe Singleton non intenzionale.
Prendere in considerazione l'esempio riportato di seguito. Nella sezione seguente dell'esempio viene descritta la definizione di una classe Aquarium. La classe definisce la proprietà di dipendenza di tipo insieme AquariumObjects che utilizza il tipo List<T> generico con un vincolo di tipo FrameworkElement. Nella chiamata Register(String, Type, Type, PropertyMetadata) per la proprietà di dipendenza, i metadati stabiliscono che il valore predefinito sia un nuovo oggetto List<T> generico.
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); }
...
}
Tuttavia, se si lascia inalterato il codice, quel singolo valore predefinito dell'elenco viene condiviso per tutte le istanze di Aquarium. Se si esegue il codice di test riportato di seguito, destinato a mostrare la modalità di creazione di due istanze di Aquarium separate e si aggiunge un singolo oggetto Fish diverso a ciascuna di esse, il risultato è sorprendente.
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");
Invece di contenere un solo elemento, ogni insieme ne contiene due. Questa situazione si verifica in quanto ciascun oggetto Aquarium ha aggiunto il proprio oggetto Fish all'insieme dei valori predefiniti, generato da una singola chiamata al costruttore nei metadati e pertanto condiviso tra tutte le istanze. Si tratta di una situazione non auspicata.
Per risolvere questo problema, è necessario reimpostare il valore della proprietà di dipendenza dell'insieme su un'unica istanza, come parte della chiamata al costruttore di classi. Dal momento che la proprietà è una proprietà di dipendenza di sola lettura, per impostarla viene utilizzato il metodo SetValue(DependencyPropertyKey, Object), mediante l'oggetto DependencyPropertyKey, al quale è possibile accedere solo all'interno della classe.
public Aquarium() : base()
{
SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>());
}
A questo punto, se si esegue nuovamente questo stesso codice di test, è possibile ottenere i risultati previsti, in cui ciascun oggetto Aquarium supporta il proprio insieme univoco.
Se si sceglie una proprietà dell'insieme con possibilità di accesso in lettura/scrittura, questo modello presenta una piccola variazione. In tal caso, è possibile chiamare la funzione di accesso set pubblica del costruttore per eseguire l'inizializzazione, che esegue la chiamata della firma non chiave di SetValue(DependencyProperty, Object) all'interno del wrapper impostato, utilizzando un identificatore DependencyProperty pubblico.
Creazione di report relativi alle modifiche dei valori di associazione nelle proprietà dell'insieme
Una proprietà dell'insieme che costituisce essa stessa una proprietà di dipendenza non crea automaticamente dei report delle modifiche per le relative sottoproprietà. La creazione di associazioni all'interno di un insieme può impedire all'associazione di creare report delle modifiche, invalidando in tal modo alcuni scenari di associazione dati. Tuttavia, se si utilizza FreezableCollection<T> come tipo insieme, i report delle modifiche della sottoproprietà apportate agli elementi contenuti nell'insieme vengono creati correttamente e l'associazione funziona nel modo previsto.
Per attivare l'associazione di sottoproprietà in un insieme di oggetti di dipendenza, creare la proprietà dell'insieme come tipo FreezableCollection<T>, con un vincolo di tipo per quell'insieme per qualsiasi classe derivata DependencyObject.
Vedere anche
Concetti
Cenni preliminari sull'associazione dati
Cenni preliminari sulle proprietà di dipendenza
Proprietà Dependency personalizzate
Metadati della proprietà di dipendenza