Condividi tramite


Ambiti dei nomi WPF

Aggiornamento: novembre 2007

Gli ambiti dei nomi rappresentano sia un concetto sia gli oggetti di programmazione tramite cui vengono archiviate le relazioni tra i nomi definiti XAML di oggetti e i relativi equivalenti delle istanze. Gli ambiti dei nomi nel codice gestito WPF vengono creati durante il caricamento delle pagine per un'applicazione XAML. Gli ambiti dei nomi come oggetto di programmazione vengono definiti dall'interfaccia INameScope e sono anche implementati dalla classe pratica NameScope.

Nel presente argomento sono contenute le seguenti sezioni.

  • Ambiti dei nomi in applicazioni XAML caricate
  • Ambiti dei nomi negli stili e nei modelli
  • Ambiti dei nomi e API relative ai nomi
  • Argomenti correlati

Ambiti dei nomi in applicazioni XAML caricate

Gli ambiti dei nomi vengono creati nell'elemento radice per una pagina XAML al momento dell'elaborazione di tale pagina. Ogni nome specificato all'interno della pagina viene aggiunto a un ambito dei nomi pertinente. Gli elementi che rappresentano elementi radice comuni (ad esempio Page e Window) controllano sempre un ambito dei nomi. Se un elemento quale FrameworkElement o FrameworkContentElement è l'elemento radice della pagina nel markup, un processore XAML aggiunge in modo implicito una radice Page affinché Page possa fornire un ambito dei nomi. Un ambito dei nomi viene creato anche se inizialmente non viene definito alcun attributo Name o x:Name in XAML.

Se si tenta di utilizzare due volte lo stesso nome in qualsiasi ambito dei nomi, viene generata un'eccezione. Per XAML che presenta code-behind e fa parte di un'applicazione compilata, l'eccezione viene generata quando si crea la classe generata per la pagina.

Aggiunta di elementi alle strutture ad albero degli elementi analizzati

Qualsiasi aggiunta alla struttura ad albero degli elementi dopo il caricamento e l'elaborazione iniziale deve chiamare l'implementazione adatta di RegisterName per la classe che definisce l'ambito dei nomi. In caso contrario, non è possibile fare riferimento all'oggetto aggiunto per nome tramite metodi come FindName. La sola impostazione di una proprietà Name (o Attributo x:Name) non consente di registrare il nome in alcun ambito dei nomi. Anche l'aggiunta di un elemento denominato alla struttura ad albero di un elemento che dispone di un ambito dei nomi non comporta la registrazione del nome nell'ambito dei nomi. Anche se gli ambiti dei nomi possono essere nidificati, generalmente i nomi vengono registrati nell'ambito dei nomi presente sull'elemento radice, pertanto il percorso dell'ambito dei nomi equivale all'ambito dei nomi che sarebbe stato creato in una pagina XAML caricata equivalente. Lo scenario più comune per gli sviluppatori di applicazioni è costituito dall'utilizzo di RegisterName per registrare nomi nell'ambito dei nomi sulla radice corrente. RegisterName fa parte di un'importante scenario per la ricerca di storyboard che verranno eseguiti come animazioni. Per ulteriori informazioni, vedere Cenni preliminari sugli storyboard. Se si chiama RegisterName su un elemento diverso dall'elemento radice nello stesso albero logico, il nome viene comunque registrato nell'elemento più vicino alla radice, come se fosse stato chiamato RegisterName sull'elemento radice.

Ambiti dei nomi nel codice

Per le applicazioni create a livello di codice e non da XAML caricato, l'elemento radice deve implementare INameScope oppure essere una classe derivata FrameworkElement o FrameworkContentElement, per supportare un ambito dei nomi.

Inoltre, per qualsiasi elemento che non viene caricato ed elaborato da un processore XAML, l'ambito dei nomi per l'oggetto non viene creato, né inizializzato per impostazione predefinita. È necessario creare in modo esplicito un nuovo ambito dei nomi per ogni elemento nel quale si intende successivamente registrare nomi. Per creare un ambito dei nomi per un elemento, chiamare il metodo SetNameScope statico. Specificare l'elemento come parametro dependencyObject e una nuova chiamata al costruttore NameScope come parametro value.

Se l'oggetto fornito come dependencyObject per SetNameScope non è un'implementazione di INameScope, FrameworkElement o FrameworkContentElement, la chiamata a RegisterName su qualsiasi elemento figlio non avrà effetto. Se non si riesce a creare in modo esplicito il nuovo ambito dei nomi, le chiamate a RegisterName genereranno un'eccezione.

Per un esempio dell'utilizzo delle API degli ambiti dei nomi nel codice, vedere Procedura: definire un ambito del nome.

Ambiti dei nomi negli stili e nei modelli

Gli stili e i modelli in WPF offrono la possibilità di riutilizzare e riapplicare contenuto in modo semplice, ma possono anche includere elementi con nomi definiti a livello del modello. Lo stesso modello potrebbe essere utilizzato più volte in una pagina. Per questo motivo, stili e modelli definiscono entrambi i relativi ambiti dei nomi, indipendentemente dalla pagina contenitore in cui viene applicato lo stile o il modello.

Si consideri l'esempio seguente:

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Page.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
      <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
        <ContentPresenter/>
      </Border>      
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
    <Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
  </StackPanel>
</Page>

In questo caso, lo stesso modello viene applicato a due pulsanti diversi. Se i modelli non disponessero di ambiti dei nomi discreti, il nome TheBorder utilizzato nel modello provocherebbe un conflitto di nomi. Ogni creazione di un'istanza del modello dispone di un proprio ambito dei nomi, di conseguenza in questo esempio ciascun ambito dei nomi del modello di cui è stata creata un'istanza contiene esattamente un nome.

Anche gli stili ottengono il relativo ambito dei nomi, principalmente in modo tale che sia possibile assegnare determinati nomi alle parti degli storyboard. Questi nomi attivano comportamenti specifici di controllo destinati a elementi di tale nome, anche se il modello è stato ridefinito come parte della personalizzazione del controllo.

A causa degli ambiti dei nomi separati, l'individuazione di elementi denominati in un modello è più complessa rispetto all'individuazione di un elemento non basato su modelli in una pagina. Per prima cosa, è necessario determinare il modello applicato, ottenendo il valore della proprietà Template del controllo in cui è applicato il modello. Quindi, chiamare la versione del modello di FindName, passando il controllo in cui era applicato il modello come secondo parametro.

Se l'autore di un controllo genera una convenzione in cui un determinato elemento denominato in un modello applicato è la destinazione per un comportamento definito dal controllo stesso, può utilizzare il metodo GetTemplateChild dal codice di implementazione del controllo. Il metodo GetTemplateChild è protetto, di conseguenza solo l'autore del controllo può accedervi.

Se si opera dall'interno un modello ed è necessario accedere all'ambito dei nomi in cui viene applicato il modello, ottenere TemplatedParent, quindi chiamare FindName. Un esempio di questo tipo di operazione è il caso in cui si scrive l'implementazione del gestore eventi in cui verrà generato l'evento da un elemento in un modello applicato.

Ambiti dei nomi e API relative ai nomi

FrameworkElement dispone dei metodi FindName, RegisterName e UnregisterName. Se l'elemento su cui si chiamano questi metodi è proprietario di un proprio ambito dei nomi, i metodi dell'elemento vengono semplicemente chiamati nei metodi dell'ambito dei nomi. In caso contrario, l'elemento padre viene controllato per verificare se è proprietario di un ambito dei nomi e questo processo continua in modo ricorsivo fino a quando non viene trovato un ambito dei nomi (a causa del comportamento del processore XAML, è garantito che vi sia un ambito dei nomi in corrispondenza della radice). FrameworkContentElement presenta comportamenti analoghi, con l'eccezione che nessun oggetto FrameworkContentElement sarà mai proprietario di un ambito dei nomi. I metodi sono presenti in FrameworkContentElement affinché sia possibile inoltrare le chiamate in ultima analisi a un elemento padre FrameworkElement.

SetNameScope viene utilizzato per eseguire il mapping di un nuovo ambito dei nomi a un oggetto esistente. È possibile chiamare SetNameScope più di una volta per reimpostare o cancellare l'ambito dei nomi, ma non si tratta di un utilizzo comune. Inoltre, in genere GetNameScope non viene utilizzato dal codice.

Implementazioni degli ambiti dei nomi

Le classi riportate di seguito implementano direttamente INameScope:

ResourceDictionary non utilizza ambiti dei nomi, ma chiavi perché si tratta di un'implementazione di dizionario/tabella hash. L'unico motivo per cui ResourceDictionary implementa INameScope è che in questo modo può generare eccezioni al codice utente che rendono più chiara la distinzione tra un ambito dei nomi effettivo e la modalità di gestione delle chiavi di ResourceDictionary, oltre ad assicurare che gli ambiti dei nomi non vengano applicati in particolare a ResourceDictionary da parte di elementi padre.

FrameworkTemplate e Style implementano INameScope tramite definizioni di interfaccia esplicite. Le implementazioni esplicite consentono a questi ambiti dei nomi di mantenere un comportamento convenzionale quando vi si accede tramite l'interfaccia INameScope, che rappresenta il modo in cui gli ambiti dei nomi sono comunicati dai processi WPF interni. Ma le definizioni di interfaccia esplicite non fanno parte della superficie dell'API convenzionale di FrameworkTemplate e Style, poiché raramente è necessario chiamare direttamente i metodi INameScope su FrameworkTemplate e Style.

Le classi riportate di seguito definiscono il proprio ambito dei nomi, utilizzando la classe di supporto System.Windows.NameScope e collegandosi all'implementazione del relativo ambito dei nomi tramite la proprietà associata NameScope:

Vedere anche

Concetti

Spazi dei nomi XAML e mapping dello spazio dei nomi

Riferimenti

Attributo x:Name