Condividi tramite


Cenni preliminari sulle proprietà di dipendenza

Aggiornamento: novembre 2007

In Windows Presentation Foundation (WPF) viene fornita una serie di servizi che è possibile utilizzare per estendere le funzionalità di una proprietà Common Language Runtime (CLR). In genere, questi servizi vengono definiti collettivamente come sistema di proprietà WPF. Una proprietà supportata dal sistema di proprietà WPF è nota come proprietà di dipendenza. In questi cenni preliminari viene descritto il sistema di proprietà WPF e le funzionalità di una proprietà di dipendenza. Viene inoltre descritta la modalità di utilizzo delle proprietà di dipendenza esistenti in Extensible Application Markup Language (XAML) e nel codice. In questi cenni preliminari vengono anche illustrati aspetti specifici delle proprietà di dipendenza, ad esempio i metadati della proprietà di dipendenza e la creazione della proprietà di dipendenza in una classe personalizzata.

Nel presente argomento sono contenute le seguenti sezioni.

  • Prerequisiti
  • Proprietà di dipendenza e proprietà CLR
  • Proprietà di dipendenza che supportano le proprietà CLR
  • Impostazione dei valori della proprietà
  • Funzionalità della proprietà fornite da una proprietà di dipendenza
  • Precedenza del valore della proprietà di dipendenza
  • Ulteriori informazioni sulle proprietà di dipendenza
  • Argomenti correlati

Prerequisiti

In questo argomento si presuppone che l'utente disponga di una conoscenza di base di CLR e della programmazione orientata a oggetti. Per seguire gli esempi di questo argomento, è necessaria inoltre conoscere XAML e la modalità di scrittura delle applicazioni WPF. Per ulteriori informazioni, vedere Guida introduttiva a Windows Presentation Foundation.

Proprietà di dipendenza e proprietà CLR

In WPF, le proprietà vengono generalmente esposte come proprietà Common Language Runtime (CLR). A un livello di base, è possibile interagire direttamente con queste proprietà senza sapere che vengono implementate come una proprietà di dipendenza. Tuttavia, è necessario acquisire familiarità con alcune o tutte le funzionalità del sistema di proprietà WPF, in modo da poterle sfruttare.

Lo scopo delle proprietà di dipendenza consiste nel fornire un modo per calcolare il valore di una proprietà in base al valore di altri input. Questi potrebbero includere proprietà del sistema, quali temi e preferenze dell'utente, meccanismi di determinazione della proprietà JIT, ad esempio associazione dati e animazionio storyboard, modelli multiuso, quali risorse e stili oppure valori noti tramite relazioni padre-figlio con altri elementi della struttura ad albero dell'elemento. Inoltre, una proprietà di dipendenza può essere implementata per fornire una convalida autonoma, valori predefiniti, callback per il monitoraggio delle modifiche di altre proprietà, nonché un sistema che può assegnare valori della proprietà mediante la coercizione in base a potenziali informazioni di runtime. Le classi derivate possono anche modificare alcune caratteristiche specifiche di una proprietà esistente, eseguendo l'override dei metadati della proprietà di dipendenza invece dell'override dell'implementazione effettiva delle proprietà esistenti oppure della creazione di nuove proprietà.

Nel riferimento SDK, è possibile identificare la proprietà di dipendenza grazie alla sezione Informazioni sulle proprietà di dipendenza, presente nella pagina di riferimento gestita per quella proprietà. Nella sezione sono inclusi un collegamento al campo dell'identificatore DependencyProperty per quella proprietà di dipendenza e un elenco delle opzioni dei metadati impostati per quella proprietà, informazioni sull'override per classe e altri dettagli.

Proprietà di dipendenza che supportano le proprietà CLR

Le proprietà di dipendenza e il sistema di proprietà WPF estendono le funzionalità della proprietà fornendo un tipo che supporta una proprietà, come implementazione alternativa al modello standard di supporto della proprietà con un campo privato. Questo tipo è denominato DependencyProperty. L'altro tipo importante che definisce il sistema di proprietà WPF è DependencyObject. L'oggetto DependencyObject definisce la classe base che può essere registrata ed essere proprietario di una proprietà di dipendenza.

Di seguito viene riportato un riepilogo della terminologia utilizzata in questa documentazione Software Development Kit (SDK) per la descrizione delle proprietà di dipendenza:

  • Proprietà di dipendenza: una proprietà supportata da un oggetto DependencyProperty.

  • Identificatore della proprietà di dipendenza: un'istanza dell'oggetto DependencyProperty ottenuta come valore restituito quando si registra una proprietà di dipendenza e successivamente memorizzata come membro di una classe. Questo identificatore viene utilizzato come parametro in molte delle API che interagiscono con il sistema di proprietà WPF.

  • "Wrapper" CLR: le effettive implementazioni ottenute e impostate della proprietà. Queste implementazioni incorporano l'identificatore della proprietà di dipendenza utilizzandolo nelle chiamate agli oggetti GetValue e SetValue, fornendo in tal modo il supporto alla proprietà tramite il sistema di proprietà WPF.

Nell'esempio seguente viene definita la IsSpinning proprietà di dipendenza e illustrata la relazione dell'identificatore DependencyProperty con la proprietà supportata.

public static readonly DependencyProperty IsSpinningProperty = 
    DependencyProperty.Register(


...


    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

La convenzione di denominazione della proprietà e del relativo campo DependencyProperty di supporto è importante. Il nome del campo è sempre il nome della proprietà al quale viene aggiunto il suffisso Property. Per ulteriori informazioni su questa convenzione e i relativi motivi, vedere Proprietà Dependency personalizzate.

Impostazione dei valori della proprietà

Le proprietà possono essere impostate nel codice o in XAML.

Impostazione dei valori della proprietà in XAML

Nell'esempio XAML seguente viene specificato il rosso come colore di sfondo di un pulsante. In questo esempio, viene descritto un caso in cui il caricatore XAML esegue la conversione del tipo del valore di stringa semplice per un attributo XAML in un tipo WPF (un oggetto Color mediante un oggetto SolidColorBrush) nel codice generato.

<Button Background="Red" Content="Button!"/>

XAML supporta diverse sintassi per l'impostazione delle proprietà. La sintassi da utilizzare per una proprietà particolare dipende dal tipo di valore utilizzato da una proprietà e da altri fattori, quali la presenza di un convertitore dei tipi. Per ulteriori informazioni sulla sintassi XAML per l'impostazione delle proprietà, vedere Cenni preliminari su XAML e Terminologia della sintassi XAML.

Nell'esempio XAML seguente viene mostrato lo sfondo di un altro pulsante, come esempio di sintassi senza attributi. Questa volta, invece di impostare un semplice colore a tinta unita, lo sfondo viene impostato su un'immagine, con un elemento che rappresenta tale immagine e la relativa origine, specificate come un attributo dell'elemento nidificato. Si tratta di un esempio di sintassi per gli elementi proprietà.

<Button Content="Button!">
  <Button.Background>
    <ImageBrush ImageSource="wavy.jpg"/>
  </Button.Background>
</Button>

Impostazione delle proprietà nel codice

L'impostazione dei valori della proprietà di dipendenza nel codice consiste, in genere, solo in una chiamata all'implementazione definita esposta dal "wrapper" CLR.

Button myButton = new Button();
myButton.Width = 200.0;

Anche l'ottenimento di un valore della proprietà prevede sostanzialmente una chiamata all'implementazione del "wrapper" ottenuta:

double whatWidth;
whatWidth = myButton.Width;

È inoltre possibile chiamare direttamente le API del sistema di proprietà GetValue e SetValue. In genere, questa operazione non è necessaria se si stanno utilizzando proprietà esistenti (i wrapper sono più utili e forniscono una migliore esposizione della proprietà per gli strumenti dello sviluppatore), tuttavia la chiamata diretta delle API risulta appropriata per determinati scenari.

È anche possibile impostare le proprietà in XAML e successivamente accedervi nel codice tramite code-behind. Per informazioni dettagliate, vedere Code-behind e XAML.

Funzionalità della proprietà fornite da una proprietà di dipendenza

Una proprietà di dipendenza fornisce funzionalità che consentono di estendere la funzionalità di una proprietà, rispetto a una proprietà supportata da un campo. Spesso, ciascuna di queste funzionalità rappresenta o supporta una funzione specifica dell'intero insieme di funzioni WPF:

  • Risorse

  • Associazione dati

  • Stili

  • Animations

  • Override dei metadati

  • Ereditarietà del valore della proprietà

  • Integrazione della finestra di Progettazione WPF

Risorse

Un valore della proprietà di dipendenza può essere impostato facendo riferimento a una risorsa. Le risorse in genere vengono specificate come elementi figlio di un elemento radice della pagina o dell'applicazione (questi percorsi consentono un accesso più semplice alla risorsa). Nell'esempio seguente viene illustrato come definire una risorsa SolidColorBrush.

<DockPanel.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>

Una volta definita, è possibile fare riferimento alla risorsa e utilizzarla per fornire un valore della proprietà:

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

A questa risorsa particolare viene fatto riferimento come Estensione del markup DynamicResource (in XAML è possibile utilizzare un riferimento di risorsa statica o dinamica). Per utilizzare un riferimento di risorsa dinamica, è necessario eseguire l'impostazione su una proprietà di dipendenza, in modo che il sistema di proprietà WPF attivi l'utilizzo spedifico del riferimento di risorsa dinamica. Per ulteriori informazioni, vedere Cenni preliminari sulle risorse.

Nota

Le risorse vengono considerate come valore locale, per cui se si imposta un altro valore locale, il riferimento di risorsa sarà eliminato. Per informazioni dettagliate, vedere Precedenza del valore della proprietà di dipendenza.

Associazione dati

Una proprietà di dipendenza può fare riferimento a un valore tramite l'associazione dati. Quest'ultima funziona tramite una sintassi per estensione di markup specifica in XAML o mediante l'oggetto Binding nel codice. Con l'associazione dati, la determinazione del valore della proprietà finale viene rinviata fino al runtime, momento in cui il valore viene ottenuto da un'origine dati.

Nell'esempio seguente viene impostata la proprietà Content per un oggetto Button, utilizzando un'associazione in XAML. L'associazione utilizza un contesto dati ereditato e un'origine dati XmlDataProvider (non visualizzata). L'associazione stessa specifica la proprietà di origine desiderata mediante l'oggetto XPath all'interno dell'origine dati.

<Button Content="{Binding XPath=Team/@TeamName}"/>

Nota

Le associazioni vengono considerate come valore locale, per cui se si imposta un altro valore locale, l'associazione sarà eliminata. Per informazioni dettagliate, vedere Precedenza del valore della proprietà di dipendenza.

Le proprietà di dipendenza o la classe DependencyObject non supportano in modo nativo l'oggetto INotifyPropertyChanged per la produzione delle notifiche delle modifiche del valore della proprietà di origine DependencyObject per le operazioni di associazione dati. Per ulteriori informazioni su come creare proprietà da utilizzare nell'associazione dati che consentano di segnalare modifiche di una destinazione di associazione dati, vedere Cenni preliminari sull'associazione dati.

Stili

Stili e modelli sono due degli scenari principali che giustificano l'utilizzo delle proprietà di dipendenza. Gli stili sono particolarmente utili per l'impostazione di proprietà che definiscono l'interfaccia utente dell'applicazione. In genere vengono definiti come risorse in XAML e interagiscono con il sistema di proprietà in quanto di solito contengono metodi di impostazione per proprietà particolari, nonché "trigger" che modificano un valore della proprietà in base al valore in tempo reale per un'altra proprietà.

Nell'esempio seguente viene creato uno stile molto semplice (definito all'interno di un dizionario Resources, non visualizzato) che viene successivamente applicato direttamente alla proprietà Style di un oggetto Button. Il metodo di impostazione dello stile imposta la proprietà Background di un oggetto Button a cui è stato applicato uno stile sul colore verde.

<Style x:Key="GreenButtonStyle">
  <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>

Per ulteriori informazioni, vedere Applicazione di stili e modelli.

Animations

Alle proprietà di dipendenza è possibile aggiungere un'animazione. Quando un'animazione viene applicata ed è in esecuzione, il valore a cui è stata aggiunta un'animazione opera a un livello di precedenza superiore rispetto a qualsiasi altro valore (ad esempio un valore locale) di cui la proprietà dispone.

Nell'esempio seguente viene aggiunta un'animazione all'oggetto Background in una proprietà Button. Tecnicamente, all'oggetto Background viene aggiunta un'animazione utilizzando la sintassi per elementi della proprietà per specificare un oggetto SolidColorBrush vuoto come oggetto Background, quindi la proprietà Color di quell'oggetto SolidColorBrush è la proprietà a cui viene aggiunta direttamente l'animazione.

<Button>I am animated
  <Button.Background>
    <SolidColorBrush x:Name="AnimBrush"/>
  </Button.Background>
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation
            Storyboard.TargetName="AnimBrush" 
            Storyboard.TargetProperty="(SolidColorBrush.Color)"
            From="Red" To="Green" Duration="0:0:5" 
            AutoReverse="True" RepeatBehavior="Forever" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Button.Triggers>
</Button>

Per ulteriori informazioni sull'animazione di proprietà, vedere Cenni preliminari sull'animazione e Cenni preliminari sugli storyboard.

Override dei metadati

È possibile modificare determinati comportamenti di una proprietà di dipendenza eseguendo l'override dei metadati per quella proprietà, quando si deriva dalla classe che registra originariamente la proprietà di dipendenza. L'esecuzione dell'override dei metadati si basa sull'identificatore DependencyProperty. L'esecuzione dell'override dei metadati non richiede una nuova implementazione della proprietà. La modifica dei metadati viene gestita in modo nativo dal sistema di proprietà; ogni classe contiene, potenzialmente, i metadati specifici per tutte le proprietà ereditate dalle classi base, in base al tipo.

Nell'esempio seguente viene eseguito l'override dei metadati per una proprietà di dipendenza DefaultStyleKey. L'esecuzione dell'override dei metadati di questa particolare proprietà di dipendenza fa parte di un modello di implementazione che consente di creare controlli che possono utilizzare stili predefiniti dai temi.

public class SpinnerControl : ItemsControl
{
    static SpinnerControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl), 
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
    }
}

Per ulteriori informazioni sull'override o su come ottenere i metadati delle proprietà, vedere Metadati della proprietà di dipendenza.

Ereditarietà del valore della proprietà

Un elemento può ereditare il valore di una proprietà di dipendenza dal relativo elemento padre nella struttura ad albero.

Nota

Il comportamento dell'ereditarietà del valore della proprietà non viene attivato a livello globale per tutte le proprietà di dipendenza, poiché il tempo di calcolo per l'ereditarietà influisce negativamente sulle prestazioni. In genere, l'ereditarietà del valore della proprietà viene attivata solo per le proprietà in cui uno scenario particolare suggerisce che tale ereditarietà è appropriata. La possibilità di ereditare di una proprietà di dipendenza può essere determinata consultando la sezione relativa alle informazioni sulle proprietà di dipendenza per una determinata proprietà di dipendenza, nel riferimento SDK.

Nell'esempio seguente viene descritta un'associazione e impostata la proprietà DataContext che specifica l'origine dell'associazione, non illustrata nell'esempio di associazione precedente. Il valore della proprietà DataContext viene ereditato, pertanto qualsiasi associazione successiva negli elementi figlio non deve rispettare l'origine specificata come oggetto DataContext nell'elemento StackPanel padre.

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

Per ulteriori informazioni, vedere Ereditarietà del valore della proprietà.

Integrazione della finestra di Progettazione WPF

Un controllo personalizzato con proprietà implementate come proprietà di dipendenza riceverà un supporto Progettazione Windows Presentation Foundation (WPF) per Visual Studio appropriato. Un esempio è rappresentato dalla capacità di modificare proprietà di dipendenza dirette e associate tramite la finestra Proprietà. Per ulteriori informazioni, vedere Cenni preliminari sulla modifica di controlli.

Precedenza del valore della proprietà di dipendenza

Quando si ottiene il valore di una proprietà di dipendenza, si ottiene un valore che era stato impostato in quella proprietà tramite uno qualsiasi degli altri input basati sulla proprietà che partecipano al sistema di proprietà di WPF. La precedenza del valore della proprietà di dipendenza consente a una varietà di scenari relativi alla modalità di ottenimento dei valori da parte delle proprietà di interagire in modo prevedibile.

Prendere in considerazione l'esempio riportato di seguito. Nell'esempio viene incluso uno stile applicato a tutti i pulsanti e alle relative proprietà Background; tuttavia viene anche specificato un pulsante con un valore Background impostato localmente.

Nota

Nella documentazione SDK i termini "valore locale" o "valore impostato localmente" vengono utilizzati talvolta per la descrizione delle proprietà di dipendenza. Un valore impostato localmente è un valore della proprietà che viene impostato direttamente in un'istanza di oggetto nel codice o come attributo di un elemento in XAML.

In pratica, per il primo pulsante la proprietà viene impostata due volte, tuttavia viene applicato solo un valore: il valore con la precedenza più alta. Un valore impostato localmente ha la massima precedenza (eccetto per un'animazione in esecuzione; tuttavia, in questo esempio non viene applicata nessuna animazione), pertanto per lo sfondo del primo pulsante viene utilizzato il valore impostato localmente anziché il valore del metodo di impostazione dello stile. Il secondo pulsante non dispone di un valore locale (e di nessun altro valore con precedenza più elevata rispetto a un metodo di impostazione dello stile), pertanto lo sfondo di quel pulsante proviene dal metodo di impostazione dello stile.

<StackPanel>
  <StackPanel.Resources>
    <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
     <Setter Property="Background" Value="Red"/>
    </Style>
  </StackPanel.Resources>
  <Button Background="Green">I am NOT red!</Button>
  <Button>I am styled red</Button>
</StackPanel>

Ragioni dell'esistenza della precedenza della proprietà di dipendenza

In genere, non si desidera che gli stili vengano sempre applicati e che nascondano persino un valore impostato localmente di un singolo elemento (altrimenti sarebbe molto difficile utilizzare gli stili o gli elementi in generale). Pertanto, i valori che provengono dagli stili operano a un livello di precedenza inferiore rispetto a un valore impostato localmente. Per un elenco più completo delle proprietà di dipendenza e per la possibile provenienza di un valore effettivo di una proprietà di dipendenza, vedere Precedenza del valore della proprietà di dipendenza.

Nota

Molte proprietà definite negli elementi WPF non sono proprietà di dipendenza. In generale, le proprietà vengono implementate come proprietà di dipendenza solo quando è necessario supportare almeno uno degli scenari attivati dal sistema di proprietà: associazione dati, applicazione degli stili, animazione, supporto del valore predefinito, ereditarietà, proprietà associate o annullamento della convalida.

Ulteriori informazioni sulle proprietà di dipendenza

  • Una proprietà associata è un tipo di proprietà che supporta una sintassi specializzata in XAML. Una proprietà associata spesso non dispone di una corrispondenza 1:1 con una proprietà Common Language Runtime (CLR) e non è necessariamente una proprietà di dipendenza. Lo scopo tipico di una proprietà associata consiste nel consentire agli elementi figlio di segnalare i valori della proprietà a un elemento padre, anche se quest'ultimo e l'elemento figlio non possiedono tale proprietà, come parte degli elenchi dei membri della classe. Uno scenario principale prevede la possibilità per gli elementi figlio di informare l'elemento padre del modo in cui vengono presentati nell'interfaccia utente; per un esempio, vedere Dock o Left. Per informazioni dettagliate, vedere Cenni preliminari sulle proprietà associate.

  • Gli sviluppatori di componenti o di applicazioni possono decidere di creare una proprietà di dipendenza personalizzata al fine di attivare funzionalità quali l'associazione dati o il supporto degli stili oppure per il supporto dell'annullamento della convalida e della coercizione del valore. Per informazioni dettagliate, vedere Proprietà Dependency personalizzate.

  • Generalmente, le proprietà di dipendenza devono essere considerate come proprietà pubbliche, accessibili o almeno individuabili da parte di qualsiasi chiamante con accesso a un'istanza. Per informazioni dettagliate, vedere Sicurezza della proprietà di dipendenza.

Vedere anche

Concetti

Proprietà Dependency personalizzate

Proprietà di dipendenza di sola lettura

Cenni preliminari su XAML

Architettura WPF