Compartilhar via


Namescopes WPF

Namescopes são tanto um conceito quanto objetos de programação que armazenam as relações entre os nomes de objetos definidos XAML e seus equivalentes de instância. Namescopes em um código gerenciado WPF são criados ao carregar as páginas para um aplicativo XAML. Namescopes como o objeto de programação são definidos pela interface INameScope e também são implementados pela classe prática NameScope.

Este tópico contém as seguintes seções.

  • Namescopes em aplicativos XAML carregados
  • Namescopes em estilos e modelos
  • Namescopes e APIs Relacionadas a Nomes
  • Tópicos relacionados

Namescopes em aplicativos XAML carregados

Namescopes são criados no elemento raiz para uma página XAML quando a página é processada. Cada nome especificado dentro da página é adicionado a um namescope pertinente. Elementos que são elementos raiz comuns (por exemplo, Page, e Window) sempre controlar um namescope. Se um elemento, sistema autônomo FrameworkElement ou FrameworkContentElement é o elemento raiz da página na marcação, um XAML processador adicionará um Page raiz implicitamente, para que o Page pode fornecer um namescope. Um namescope é criado mesmo se nenhum atributo Name ou x:Name é definido na caixa XAML inicialmente.

Se você tentar usar o mesmo nome duas vezes em qualquer namescope, uma exceção é gerada. Para XAML que tem código de lógica e é parte de um aplicativo compilado, essa exceção é gerada ao criar a classe gerada para a página.

Adicionando elementos ao elemento de árvore processada

Quaisquer inclusões ao elemento de árvore após carregamento e processamento iniciais devem chamar a implementação apropriada de RegisterName para a classe que define o namescope. Caso contrário, o objeto adicionado não pode ser referenciado pelo nome através de métodos como FindName. Simplesmente configurar uma propriedade Name (ou x:Name Attribute) não registra esse nome em qualquer namescope. Adicionar um elemento nomeado a um elemento de árvore que tenha um namescope também não registra o nome para o namescope. Embora namescopes possam ser aninhados, você geralmente registra nomes para o namescope que existe no elemento raiz, de modo que o local de seu namescope seja análogo ao namescope que teria sido criado em uma página XAML carregada equivalente. O cenário mais comum para desenvolvedores de aplicativos é que você usará RegisterName para registrar nomes em namescope na raiz corrente. RegisterName faz parte de um cenário importante para a localização de esboços seqüenciais que serão executado sistema autônomo animações. Para obter mais informações, consulte Visão geral sobre Storyboards. Se você chamar RegisterName em um elemento diferente do elemento raiz na mesma árvore lógica, o nome ainda está registrado para o elemento mais próximo da raiz, como se você tivesse chamado RegisterName no elemento raiz.

Namescopes em código

Para aplicativos que são criados por programação, e não carregados por XAML, o elemento raiz deve implementar INameScope, ou ser uma classe derivada de FrameworkElement ou FrameworkContentElement, para suporte a um namescope.

Além disso, para qualquer elemento que não é carregado e processado por um processador XAML, o namescope para o objeto não é criado ou inicializado por padrão. Você deve criar explicitamente um novo namescope para qualquer elemento para o qual você pretende registrar nomes posteriormente. Para criar um namescope de um elemento, chame o método estático SetNameScope. Especificar o elemento como o parâmetro dependencyObject e uma nova chamada de construtor NameScope como o parâmetro value.

Se o objeto fornecido como dependencyObject para SetNameScope não for uma implementação INameScope, FrameworkElement ou FrameworkContentElement, então chamar RegisterName em qualquer elemento filho não terá efeito. Se você não conseguir criar o novo namescope explicitamente, chamadas a RegisterName gerarão uma exceção.

Para obter um exemplo do uso do namescope APIs no código, consulte Como: Definir um escopo de nomes.

Namescopes em estilos e modelos

Estilos e modelos no WPF oferecem a capacidade para reutilização e reaplicar o conteúdo de uma maneira simples, mas os estilos e modelos podem também incluir elementos com nomes definidos no nível do modelo. Esse mesmo modelo pode ser usado várias vezes em uma página. Por esse motivo, ambos os estilos e modelos definem seus próprios namescopes, independente da página à qual o estilo ou modelo é aplicado.

Considere o exemplo a seguir:

<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>

Aqui, o mesmo modelo é aplicado aos dois botões diferentes. Se os modelos não tivessem distintos namescopes, o nome TheBorder usado no modelo causaria um conflito de nomes. Cada instanciação do modelo tem seu próprio namescope, então neste exemplo cada namescope de modelo instanciado conteria exatamente um nome.

Estilos também obter seu próprio namescope, principalmente para que partes de storyboards possam ter determinados nomes atribuídos. Esses nomes ativam controle de comportamentos específicos que terão como alvo elementos desse nome, mesmo se o modelo foi redefinido como parte da personalização de controle.

Devido a namescopes separados, encontrar elementos nomeados em um modelo é mais desafiador do que localizar um elemento não modelo em uma página. Você precisará primeiro determinar o modelo aplicado, recuperando o valor da propriedade Template do controle onde o modelo é aplicado. Em seguida, você deve chamar a versão de modelo de FindName, passando o controle onde o modelo foi aplicado como o segundo parâmetro.

Se você for um autor de controle e estiver gerando uma convenção em que um específico elemento nomeado em um modelo aplicado é o destino para um comportamento que é definido pelo próprio controle, você pode usar o método GetTemplateChild do seu código de implementação de controle. O método GetTemplateChild é protegido, portanto somente o autor do controle tem acesso a ele.

Se você estiver trabalhando de dentro de um modelo e precise ir para o namescope onde o modelo é aplicado, recupere TemplatedParent e dali chame FindName. Um exemplo de como trabalhar no modelo seria se você estiver escrevendo a implementação de um manipulador de eventos onde o evento será gerado de um elemento em um modelo aplicado.

Namescopes e APIs Relacionadas a Nomes

FrameworkElement possui métodos FindName, RegisterName e UnregisterName. Se o elemento no qual você chamar esses métodos possui um namescope, os métodos do elemento simplesmente chamam os métodos do namescope. Caso contrário, o elemento pai é verificado para ver se ele é proprietário de um namescope e esse processo continua repetidamente até que seja encontrada uma namescope (por causa do XAML comportamento do processador, lá é garantidamente um namescope na raiz). FrameworkContentElement possui análogos comportamentos, com exceção de que nenhum FrameworkContentElement nunca será o proprietário um namescope. Os métodos existem no FrameworkContentElement para que as chamadas podem ser encaminhadas eventualmente para um elemento pai FrameworkElement.

SetNameScope é usado para mapear um novo namescope para um objeto existente. Você pode chamar SetNameScope mais de uma vez para redefinir ou limpar o namescope, mas isso não é uma prática comum. Além disso, GetNameScope geralmente não é usado em código.

Implementações de Namescope

As seguintes classes implementam INameScope diretamente:

ResourceDictionary não usa namescopes; ele usa chaves em vez disso, porque ele é uma implementação de dicionário de tabela hash. A única razão de ResourceDictionary implementar INameScope é para que ele possa lançar exceções para o código do usuário que ajudam a esclarecer a distinção entre um namescope verdadeiro e como um ResourceDictionary trata as chaves, e também para garantir que namescopes não são particularmente aplicados a um ResourceDictionary pelos elementos pais.

FrameworkTemplate e Style implementam INameScope através de definições explícitas de interface. As implementações explícitas permitem que esses namescopes se comportem de modo convencional quando forem acessados através da interface INameScope, que é como namescopes são expressos por processos internos WPF. Mas as definições de interface explícita não fazem parte da superfície de API convencional da FrameworkTemplate e Style, pois você raramente precisará chamar o INameScope métodos em FrameworkTemplate e Style diretamente.

As seguintes classes definem seus próprios namescopes, usando a classe auxiliar System.Windows.NameScope e conectando-se à sua implementação de namescope por meio da propriedade anexa NameScope:

Consulte também

Conceitos

Espaços de nomes XAML e mapeamentos de espaços de nomes

Referência

x:Name Attribute