Condividi tramite


Ambiti dei nomi XAML WPF

Gli ambiti dei nomi di XAML sono un concetto che serve a identificare gli oggetti definiti in XAML. I nomi in un ambito dei nomi XAML possono essere usati per stabilire relazioni tra i nomi definiti da XAML degli oggetti e i relativi equivalenti di istanza in un albero di oggetti. In genere, i namescopes XAML nel codice gestito di WPF vengono creati quando si caricano le radici delle singole pagine XAML per un'applicazione XAML. Gli ambiti dei nomi XAML come oggetto di programmazione sono definiti dall'interfaccia INameScope e vengono implementati anche dalla classe pratica NameScope.

Ambiti dei nomi nelle applicazioni XAML caricate

In un contesto di programmazione o informatica più ampio, i concetti di programmazione spesso includono il principio di un identificatore univoco o un nome che può essere usato per accedere a un oggetto. Per i sistemi che usano identificatori o nomi, l'ambito dei nomi definisce i limiti all'interno del quale un processo o una tecnica cercherà se viene richiesto un oggetto di tale nome o i limiti in cui viene applicata l'univocità dei nomi di identificazione. Questi principi generali sono veri per gli ambiti dei nomi XAML. In WPF, i namescope XAML vengono creati sull'elemento radice per una pagina XAML quando la pagina viene caricata. Ogni nome specificato all'interno della pagina XAML a partire dalla radice della pagina viene aggiunto a un ambito dei nomi XAML pertinente.

In XAML WPF gli elementi che sono elementi radice comuni (ad esempio Pagee Window) controllano sempre un ambito dei nomi XAML. Se un elemento come FrameworkElement o FrameworkContentElement è l'elemento radice della pagina nel markup, un processore XAML aggiunge in modo implicito una radice Page in modo che l'Page possa fornire un ambito dei nomi XAML funzionante.

Nota

Le azioni di compilazione WPF creano un namescope XAML per una produzione XAML anche se non vengono definiti attributi Name o x:Name su alcun elemento del markup XAML.

Se si tenta di usare lo stesso nome due volte in qualsiasi ambito dei nomi XAML, viene generata un'eccezione. Per XAML WPF che include code-behind ed è parte di un'applicazione compilata, l'eccezione viene sollevata in fase di build dalle azioni di compilazione WPF, quando si crea la classe generata per la pagina durante la compilazione iniziale del markup. Per XAML che non è compilato tramite alcuna azione di build, potrebbero essere sollevate eccezioni legate a problemi di ambito dei nomi di XAML quando questo viene caricato. I progettisti XAML potrebbero anche prevedere problemi di ambito dei nomi XAML in fase di progettazione.

Aggiunta di oggetti agli alberi degli oggetti di runtime

Il momento in cui XAML viene analizzato rappresenta il momento in cui viene creato e definito un ambito dei nomi XAML WPF. Se si aggiunge un oggetto a un albero di oggetti in un momento specifico dopo l'analisi del codice XAML che ha prodotto tale albero, un valore Name o x:Name sul nuovo oggetto non aggiorna automaticamente le informazioni in un ambito dei nomi XAML. Per aggiungere un nome per un oggetto in un ambito dei nomi XAML WPF dopo il caricamento di XAML, devi chiamare l'implementazione appropriata di RegisterName sull'oggetto che definisce l'ambito dei nomi XAML, che in genere è la radice della pagina XAML. Se il nome non è registrato, l'oggetto aggiunto non può essere referenziato per nome tramite metodi come FindNamee non è possibile usare tale nome per il targeting dell'animazione.

Lo scenario più comune per gli sviluppatori di applicazioni è che tu utilizzerai RegisterName per registrare i nomi nello spazio dei nomi XAML sulla radice attuale della pagina. RegisterName fa parte di uno scenario importante per gli storyboard che hanno come obiettivo gli oggetti nelle animazioni. Per altre informazioni, vedere Panoramica degli Storyboard .

Se chiami RegisterName su un oggetto diverso da quello che definisce l'ambito dei nomi XAML, il nome è comunque registrato nell'ambito dei nomi XAML in cui si trova l'oggetto chiamante, come se avessi chiamato RegisterName sull'oggetto che definisce l'ambito dei nomi XAML.

Ambiti dei nomi XAML nel codice

È possibile creare e quindi usare ambiti dei nomi XAML nel codice. Le API e i concetti coinvolti nella creazione del namescope XAML sono gli stessi anche per un uso esclusivamente di codice, perché il processore XAML per WPF usa queste API e concetti quando elabora XAML stesso. I concetti e l'API esistono principalmente allo scopo di poter trovare oggetti in base al nome all'interno di un albero di oggetti definito in genere parzialmente o interamente in XAML.

Per le applicazioni create a livello di codice e non da XAML caricato, l'oggetto che definisce un ambito dei nomi XAML deve implementare INameScopeo essere una classe derivata FrameworkElement o FrameworkContentElement, per supportare la creazione di un ambito dei nomi XAML nelle relative istanze.

Inoltre, per qualsiasi elemento non caricato ed elaborato da un processore XAML, l'ambito dei nomi XAML per l'oggetto non viene creato o inizializzato per impostazione predefinita. Devi creare in modo esplicito un nuovo ambito dei nomi XAML per qualsiasi oggetto in cui intendi registrare i nomi successivamente. Per creare un ambito dei nomi XAML, chiamare il metodo statico SetNameScope. Specificare l'oggetto proprietario come parametro dependencyObject e una nuova chiamata del costruttore NameScope come parametro value.

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

Per un esempio di uso delle API dell'ambito dei nomi XAML nel codice, vedere Definire un ambito di nome.

Ambiti dei nomi XAML negli stili e nei modelli

Gli stili e i modelli in WPF consentono di riutilizzare e riapplicare il contenuto in modo semplice. Tuttavia, gli stili e i modelli possono includere anche elementi con nomi XAML definiti a livello di modello. Lo stesso modello può essere usato più volte in una pagina. Per questo motivo, gli stili e i modelli definiscono entrambi i propri ambiti dei nomi XAML, indipendentemente dalla posizione in un albero di oggetti in cui viene applicato lo stile o il modello.

Si consideri l'esempio seguente:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://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 hanno ambiti dei nomi XAML discreti, il nome TheBorder usato nel modello provocherebbe un conflitto di nomi nell'ambito dei nomi XAML. Ogni istanza del modello ha un proprio ambito dei nomi XAML, quindi in questo esempio ogni ambito dei nomi XAML di ogni modello creato conterrà esattamente un nome.

Gli stili definiscono anche il proprio ambito dei nomi XAML, principalmente in modo che parti degli storyboard possano avere nomi specifici assegnati. Questi nomi consentono di controllare comportamenti specifici che saranno destinati agli elementi di tale nome, anche se il modello è stato ridefinito come parte della personalizzazione del controllo.

A causa degli ambiti dei nomi XAML separati, la ricerca di elementi nominati in un modello è più complessa rispetto alla ricerca di un elemento nominato non modellato in una pagina. Per prima cosa è necessario determinare il modello applicato, ottenendo il valore della proprietà Template del controllo in cui viene applicato il modello. Chiama quindi la versione del modello di FindName, passando il controllo dove è stato applicato il modello come secondo parametro.

Se si è un autore di controlli e si sta generando una convenzione in cui un particolare elemento denominato in un modello applicato è la destinazione per un comportamento definito dal controllo stesso, è possibile utilizzare il metodo GetTemplateChild dal codice di implementazione del controllo. Il metodo GetTemplateChild è protetto, quindi solo l'autore del controllo può accedervi.

Se si lavora dall'interno di un modello ed è necessario accedere all'ambito dei nomi XAML in cui viene applicato il modello, ottieni il valore di TemplatedParente quindi chiama FindName là. Un esempio di utilizzo all'interno del modello è se si scrive l'implementazione del gestore eventi in cui l'evento verrà generato da un elemento in un modello applicato.

FrameworkElement include metodi FindName, RegisterName e UnregisterName. Se l'oggetto su cui chiami questi metodi è proprietario di un ambito dei nomi XAML, i metodi richiamano i metodi dell'ambito dei nomi XAML pertinente. In caso contrario, l'elemento padre viene controllato per verificare se è proprietario di un ambito dei nomi XAML e questo processo continua in modo ricorsivo fino a quando non viene trovato un ambito dei nomi XAML (a causa del comportamento del processore XAML, è garantito un ambito dei nomi XAML nella radice). FrameworkContentElement ha comportamenti analoghi, con l'eccezione che nessun FrameworkContentElement sarà mai proprietario di un ambito dei nomi XAML. I metodi presenti su FrameworkContentElement esistono affinché le chiamate possano essere inoltrate a un elemento genitore FrameworkElement.

SetNameScope viene usato per eseguire il mapping di un nuovo ambito dei nomi XAML a un oggetto esistente. Puoi chiamare SetNameScope più volte per reimpostare o cancellare l'ambito dei nomi XAML, ma questo non è un utilizzo comune. Inoltre, GetNameScope non viene in genere usato dal codice.

Implementazioni dell'ambito dei nomi XAML

Le classi seguenti implementano direttamente INameScope:

ResourceDictionary non usa nomi XAML o ambiti dei nomi ; usa invece le chiavi, perché è un'implementazione del dizionario. L'unico motivo per cui ResourceDictionary implementa INameScope è quindi in grado di generare eccezioni al codice utente che consentono di chiarire la distinzione tra un vero ambito dei nomi XAML e il modo in cui un ResourceDictionary gestisce le chiavi e anche per garantire che gli ambiti dei nomi XAML non vengano applicati a un ResourceDictionary dagli elementi padre.

FrameworkTemplate e Style implementano INameScope tramite definizioni di interfaccia esplicite. Le implementazioni esplicite consentono a questi ambiti dei nomi XAML di comportarsi convenzionalmente quando si accede tramite l'interfaccia INameScope, che è il modo in cui gli ambiti dei nomi XAML vengono comunicati dai processi interni WPF. Tuttavia, le definizioni di interfaccia esplicite non fanno parte della superficie API convenzionale di FrameworkTemplate e Style, perché raramente è necessario chiamare i metodi INameScope su FrameworkTemplate e Style direttamente e invece userebbe altre API, ad esempio GetTemplateChild.

Le classi seguenti definiscono il proprio ambito dei nomi XAML, usando la classe helper System.Windows.NameScope e connettendosi all'implementazione dell'ambito dei nomi XAML tramite la proprietà associata NameScope.NameScope:

Vedere anche