Strutture ad albero in WPF

In molte tecnologie, gli elementi e i componenti sono organizzati in una struttura ad albero in cui gli sviluppatori modificano direttamente la struttura ad albero per influire sul rendering o sul comportamento di un'applicazione. In Windows Presentation Foundation (WPF) vengono utilizzate anche molte metafore della struttura ad albero per definire le relazioni tra gli elementi del programma. In genere gli sviluppatori di WPF possono creare un'applicazione nel codice o definire parti dell'applicazione in XAML utilizzando come riferimento concettuale la metafora di struttura ad albero di oggetti, ma chiameranno un'API specifica o utilizzeranno un markup specifico a tale scopo anziché un'API di modifica della struttura ad albero di oggetti generica simile a quella utilizzata in DOM XML. WPF espone due classi di supporto che forniscono una visualizzazione della metafora di struttura ad albero, ovvero LogicalTreeHelper e VisualTreeHelper. Nella documentazione di WPF vengono inoltre utilizzati i termini struttura ad albero visuale e struttura ad albero logica, in quanto tali strutture ad albero sono utili per la comprensione di alcune funzionalità principali di WPF. In questo argomento viene definito ciò che una struttura ad albero visuale e una struttura ad albero logica rappresentano e viene descritta la relazione tra tali strutture ad albero e un concetto di struttura ad albero di oggetti complessivo. Vengono inoltre introdotte le classi LogicalTreeHelper e VisualTreeHelper.

Nel presente argomento sono contenute le seguenti sezioni.

  • Strutture ad albero in WPF
  • Albero logico
  • Struttura ad albero visuale
  • Strutture ad albero, elementi e host di contenuto
  • Attraversamento della struttura ad albero
  • Route per eventi indirizzati come "struttura ad albero"
  • Dizionari risorse e strutture ad albero
  • Argomenti correlati

Strutture ad albero in WPF

La struttura ad albero più completa in WPF è la struttura ad albero di oggetti. Se si definisce la pagina di un'applicazione in XAML e quindi si carica il file XAML, la struttura ad albero viene creata in base alle relazioni di annidamento degli elementi nel markup. Se si definisce un'applicazione o una parte dell'applicazione nel codice, la struttura ad albero verrà creata in base alla modalità utilizzata per assegnare valori di proprietà per le proprietà che implementano il modello di contenuto per un oggetto specifico. In Windows Presentation Foundation (WPF) la struttura ad albero di oggetti completa viene concettualizzata e può essere segnalata alla relativa API pubblica in due modi diversi: come struttura ad albero logica e come struttura ad albero visuale. Le distinzioni tra albero logico e struttura ad albero visuale non sono sempre necessariamente importanti, tuttavia possono talvolta causare problemi ad alcuni sottosistemi WPF e influire sulle scelte fatte nel markup o nel codice.

Sebbene la struttura ad albero logica o la struttura ad albero visuale non venga sempre modificata direttamente, la corretta comprensione dei concetti correlati all'interazione delle strutture ad albero è utile per comprendere WPF in quanto tecnologia. Il concetto di WPF come metafora di struttura ad albero di un certo tipo è anche essenziale per la comprensione del funzionamento dell'ereditarietà delle proprietà e del routing degli eventi in WPF.

NotaNota

Poiché la struttura ad albero di oggetti è più un concetto che un'API effettiva, è possibile considerare tale concetto anche un oggetto grafico.In pratica, in fase di esecuzione sussistono relazioni tra oggetti per cui la metafora di struttura ad albero non è valida.Ciononostante, in particolare con un'interfaccia utente definita in XAML, la metafora di struttura ad albero è sufficientemente pertinente da far sì che nella maggior parte della documentazione di WPF venga utilizzato il termine struttura ad albero di oggetti per fare riferimento a tale concetto generale.

Albero logico

In WPF è possibile aggiungere contenuto a elementi di interfaccia utente impostando proprietà degli oggetti di supporto per tali elementi. È possibile, ad esempio, aggiungere elementi a un controllo ListBox modificandone la proprietà Items. In questo modo, vengono aggiunti elementi nell'oggetto ItemCollection, che rappresenta il valore della proprietà Items. Analogamente, per aggiungere oggetti a un controllo DockPanel, è necessario modificare il valore della relativa proprietà Children. In questo caso, vengono aggiunti oggetti a UIElementCollection. Per un esempio di codice, vedere Procedura: aggiungere un elemento dinamicamente.

In Extensible Application Markup Language (XAML), quando si aggiungono voci di elenco in un oggetto ListBox o controlli o altri elementi di interfaccia utente in un oggetto DockPanel, è anche possibile utilizzare le proprietà Items e Children in modo esplicito o implicito, come nell'esempio seguente.

<DockPanel
  Name="ParentElement"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <!--implicit: <DockPanel.Children>-->
  <ListBox DockPanel.Dock="Top">
    <!--implicit: <ListBox.Items>-->
    <ListBoxItem>
      <TextBlock>Dog</TextBlock>
    </ListBoxItem>
    <ListBoxItem>
      <TextBlock>Cat</TextBlock>
    </ListBoxItem>
    <ListBoxItem>
      <TextBlock>Fish</TextBlock>
    </ListBoxItem>
  <!--implicit: </ListBox.Items>-->
  </ListBox>
  <Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>
  <!--implicit: </DockPanel.Children>-->
</DockPanel>

Se si elabora questo file XAML come XML in un modello DOM (Document Object Model) e sono stati inclusi i tag impostati come commenti impliciti (operazione consentita), la struttura ad albero DOM XML risultante includerà elementi per <ListBox.Items> e gli altri elementi impliciti. Poiché tuttavia XAML non viene elaborato in questo modo durante la lettura del markup e la scrittura negli oggetti, l'oggetto grafico risultante non includerà letteralmente ListBox.Items. Includerà tuttavia una proprietà ListBox denominata Items contenente una classe ItemCollection e tale classe ItemCollection sarà inizializzata ma vuota durante l'elaborazione del markup XAML di ListBox. Ogni elemento oggetto figlio presente come contenuto per ListBox verrà quindi aggiunto alla classe ItemCollection da chiamate del parser a ItemCollection.Add. Fino a questo punto, in questo esempio di elaborazione del markup XAML in una struttura ad albero di oggetti la struttura ad albero di oggetti creata sembra fondamentalmente essere la struttura ad albero logica.

La struttura ad albero logica, tuttavia, non è l'intero oggetto grafico presente per l'interfaccia utente dell'applicazione in fase di esecuzione, anche se si considerano gli elementi della sintassi implicita XAML. Ciò è dovuto principalmente agli elementi visivi e ai modelli. Si consideri, ad esempio, Button. La struttura ad albero logica indica l'oggetto Button e anche la relativa stringa Content. Nella struttura ad albero di oggetti di runtime, tuttavia, questo pulsante è molto più complesso. In particolare, la limitata visualizzazione del pulsante sullo schermo è dovuta all'applicazione di un modello di controllo Button specifico. Gli elementi visivi derivati da un modello applicato, ad esempio il controllo Border definito dal modello che prevede un bordo grigio scuro intorno al pulsante visivo, non sono specificati nella struttura ad albero logica, neanche se si osserva tale struttura in fase di esecuzione, ad esempio durante la gestione di un evento di input dall'interfaccia utente visibile e la successiva lettura della struttura ad albero logica. Per trovare gli elementi visivi del modello, è invece necessario esaminare la struttura ad albero visuale.

Per ulteriori informazioni sul mapping all'oggetto grafico creato da parte della sintassi XAML e sulla sintassi implicita in XAML, vedere Descrizione dettagliata della sintassi XAML o Cenni preliminari su XAML (WPF)

Scopo dell'albero logico

La struttura ad albero logica consente ai modelli di contenuto di scorrere rapidamente i relativi oggetti figlio e rende i modelli di contenuto estendibili. La struttura ad albero logica, inoltre, fornisce un framework per determinate notifiche, ad esempio relative al caricamento di tutti gli oggetti nella struttura ad albero logica stessa. Fondamentalmente la struttura ad albero logica è un'approssimazione di un oggetto grafico di runtime a livello di framework, che esclude elementi visivi, ma è efficace per molte operazioni di esecuzione di query sulla composizione dell'applicazione di runtime.

I riferimenti a risorse sia statiche che dinamiche, inoltre, vengono risolti cercando verso l'alto nella struttura ad albero insiemi Resources nell'oggetto richiedente iniziale, quindi continuando verso l'alto nella struttura ad albero logica e verificando ogni oggetto FrameworkElement (o FrameworkContentElement) per un altro valore Resources che contiene una classe ResourceDictionary, possibilmente contenente tale chiave. L'albero logico viene utilizzato per la ricerca delle risorse, quando sono presenti sia l'albero logico, sia la struttura ad albero visuale. Per ulteriori informazioni sui dizionari risorse e la ricerca, vedere Cenni preliminari sulle risorse.

Composizione della struttura ad albero logica

La struttura ad albero logica è definita a livello di framework WPF, a indicare che l'elemento di base WPF più pertinente per le operazioni della struttura ad albero logica è FrameworkElement o FrameworkContentElement. Come è possibile osservare se si utilizza effettivamente l'API LogicalTreeHelper, tuttavia, la struttura ad albero logica contiene talvolta nodi che non sono FrameworkElement o FrameworkContentElement. La struttura ad albero logica, ad esempio, specifica il valore Text di un oggetto TextBlock, che è una stringa.

Override dell'albero logico

Gli autori di controlli avanzati possono eseguire l'override della struttura ad albero logica tramite l'override di diverse APIs che definiscono le modalità di aggiunta o rimozione di oggetti nella struttura ad albero logica utilizzate da un oggetto o un modello di contenuto generale. Per un esempio relativo all'override dell'albero logico, vedere Procedura: eseguire l'override dell'albero logico.

Ereditarietà del valore della proprietà

L'ereditarietà del valore della proprietà opera tramite una struttura ad albero ibrida. I metadati effettivi che contengono la proprietà Inherits che consente l'ereditarietà della proprietà sono presenti nella classe FrameworkPropertyMetadataa livello di framework WPF. L'oggetto padre che contiene il valore originale e l'oggetto figlio che eredita tale valore, pertanto, devono entrambi essere FrameworkElement o FrameworkContentElement e devono entrambi far parte della stessa struttura ad albero logica. Per le proprietà WPF esistenti che supportano l'ereditarietà delle proprietà, tuttavia, l'ereditarietà dei valori di proprietà può essere mantenuta tramite un nuovo oggetto non incluso nella struttura ad albero logica. Questa caratteristica è pertinente per lo più se si desidera fare in modo che gli elementi del modello utilizzino valori di proprietà ereditati impostati sull'istanza basata sul modello o a livelli ancora superiori di composizione a livello di pagina e pertanto superiori nella struttura ad albero logica. Per garantire un funzionamento coerente dell'ereditarietà dei valori di proprietà in un limite di questo tipo, la proprietà che eredita deve essere registrata come proprietà associata. È inoltre consigliabile utilizzare questo modello se si desidera definire una proprietà di dipendenza personalizzata con un comportamento di ereditarietà della proprietà. La struttura ad albero esatta utilizzata per l'ereditarietà della proprietà non può essere completamente prevista da un metodo di utilità di una classe di supporto, persino in fase di esecuzione. Per ulteriori informazioni, vedere Ereditarietà del valore della proprietà.

Struttura ad albero visuale

In WPF, oltre al concetto di albero logico esiste anche il concetto di struttura ad albero visuale. Nella struttura ad albero visuale viene descritta la struttura degli oggetti visivi rappresentati dalla classe di base Visual. Quando si scrive un modello per un controllo, si definisce o ridefinisce la struttura ad albero visuale relativa a quel controllo. La struttura ad albero visuale è di interesse anche per gli sviluppatori che desiderano un controllo di livello inferiore sui disegni per ragioni di prestazioni e ottimizzazione. Un'esposizione della struttura ad albero visuale come parte della programmazione di applicazioni WPF convenzionale è rappresentata dal fatto che le route degli eventi per un evento indirizzato percorrono per la maggior parte la struttura ad albero visuale e non la struttura ad albero logica. Questa sottigliezza del comportamento dell'evento indirizzato potrebbe non essere immediatamente visibile, a meno che l'utente non sia un autore di controlli. Il routing di eventi nella struttura ad albero visuale consente ai controlli che implementano la composizione a livello visivo di gestire eventi o creare metodi di impostazione degli eventi.

Strutture ad albero, elementi e host di contenuto

Gli elementi di contenuto (classi che derivano da ContentElement) non fanno parte della struttura ad albero visuale, non ereditano da Visual e non dispongono di una rappresentazione visiva. Per essere visualizzato in un'interfaccia utente, un oggetto ContentElement deve essere ospitato in un host di contenuto che consista sia in un oggetto Visual sia in un partecipante della struttura ad albero logica. In genere, si tratta di un oggetto FrameworkElement. È possibile partire dal concetto che l'host di contenuto è come un "browser" per il contenuto e sceglie come visualizzare tale contenuto all'interno dell'area dello schermo controllata dall'host. Quando ospitato, il contenuto può partecipare ad alcuni processi della struttura ad albero che normalmente sono associati alla struttura ad albero visuale. Generalmente, la classe host FrameworkElement include il codice di implementazione che aggiunge tutti gli oggetti ContentElement ospitati alla route dell'evento tramite nodi secondari dell'albero logico del contenuto, anche se il contenuto ospitato non fa parte della vera struttura ad albero visuale. Questa operazione è necessaria affinché ContentElement possa originare un evento indirizzato che indirizzi a qualsiasi elemento diverso da sé stesso.

Attraversamento della struttura ad albero

La classe LogicalTreeHelper fornisce i metodi GetChildren, GetParent e FindLogicalNode per l'attraversamento dell'albero logico. Nella maggior parte dei casi, non è necessario attraversare la struttura ad albero logica dei controlli esistenti, in quanto tali controlli espongono quasi sempre i relativi elementi figlio logici come proprietà di insieme dedicata che supporta accesso all'insieme, ad esempio Add, un indicizzatore e così via. L'attraversamento della struttura ad albero è principalmente uno scenario utilizzato dagli autori di controlli che scelgono di non derivare da pattern di controllo previsti per questo scopo, ad esempio ItemsControl o Panel in cui le proprietà dell'insieme sono già definite e che intendono fornire il proprio supporto della proprietà dell'insieme.

La struttura ad albero visuale supporta anche una classe di supporto per l'attraversamento della struttura ad albero visuale, VisualTreeHelper. La struttura ad albero visuale non viene esposta in modo appropriato tramite le proprietà specifiche del controllo, pertanto la classe VisualTreeHelper rappresenta il modo migliore per attraversare la struttura ad albero visuale, se necessario per lo scenario di programmazione. Per ulteriori informazioni, vedere Cenni preliminari sul rendering della grafica WPF.

NotaNota

È talvolta necessario esaminare la struttura ad albero visuale di un modello applicato.Quando si utilizza questa tecnica, è consigliabile procedere con attenzione.Anche quando si attraversa una struttura ad albero visuale per un controllo in cui viene definito il modello, i consumer del controllo possono sempre modificare il modello impostando la proprietà Template nelle istanze. Anche l'utente finale può influire sul modello applicato modificando il tema di sistema.

Route per eventi indirizzati come "struttura ad albero"

Come indicato in precedenza, la route di qualsiasi evento indirizzato specificato percorre un singolo percorso predeterminato di una struttura ad albero che consiste in una forma ibrida delle rappresentazioni di struttura ad albero visuale e logica. La route di eventi può percorrere la struttura ad albero verso l'alto o verso il basso, a seconda che si tratti di un evento indirizzato di tunneling o di bubbling. Il concetto di route dell'evento non prevede una classe di supporto diretto che potrebbe essere utilizzata per "percorrere" la route dell'evento indipendentemente dalla generazione di un evento che effettivamente esegue l'indirizzamento. È disponibile una classe che rappresenta la route, EventRoute, tuttavia i metodi di tale classe sono generalmente riservati all'utilizzo interno.

Dizionari risorse e strutture ad albero

La ricerca nei dizionari risorse di tutte le proprietà Resources definite in una pagina attraversa fondamentalmente la struttura ad albero logica. Gli oggetti non inclusi nella struttura ad albero logica possono fare riferimento a risorse con chiave, ma la sequenza di ricerca delle risorse inizia nel punto in cui l'oggetto è connesso alla struttura ad albero logica. Poiché in WPF solo i nodi della struttura ad albero logica possono includere una proprietà Resources contenente un oggetto ResourceDictionary, l'attraversamento della struttura ad albero visuale alla ricerca di risorse con chiave da un oggetto ResourceDictionary non offre alcun vantaggio.

Tuttavia, la ricerca delle risorse può anche essere estesa oltre l'albero logico diretto. Per il markup dell'applicazione, la ricerca di risorse può quindi proseguire verso dizionari risorse a livello di applicazione e quindi verso il supporto dei temi e i valori di sistema cui viene fatto riferimento come proprietà o chiavi statiche. Se i riferimenti di risorsa sono dinamici, i temi stessi possono fare riferimento anche ai valori di sistema esterni all'albero logico del tema. Per ulteriori informazioni sui dizionari risorse e la logica di ricerca, vedere Cenni preliminari sulle risorse.

Vedere anche

Concetti

Cenni preliminari sull’input

Cenni preliminari sul rendering della grafica WPF

Cenni preliminari sugli eventi indirizzati

Inizializzazione di elementi oggetto non presenti in una struttura ad albero di oggetti

Architettura WPF