Namescopes XAML WPF

Os namescopes de XAML são um conceito que identifica objetos que são definidos em XAML. Os nomes em um namescope de XAML podem ser usados para estabelecer relações entre os nomes de objetos definidos por XAML e seus equivalentes de instância em uma árvore de objetos. Normalmente, os namescopes XAML no código gerenciado WPF são criados ao carregar as raízes de página XAML individuais para um aplicativo XAML. Os namescopes XAML como o objeto de programação são definidos pela interface e também são implementados pela INameScope classe NameScopepractical .

Namescopes em aplicativos de XAML carregados

Em um contexto mais amplo de programação ou de ciência da computação, os conceitos de programação geralmente incluem o princípio de um identificador exclusivo ou de um nome que pode ser usado para acessar um objeto. Para sistemas que usam identificadores ou nomes, o namescope define os limites dentro dos quais um processo ou uma técnica pesquisará, se um objeto com esse nome for solicitado ou os limites em que a exclusividade de nomes de identificação é imposta. Esses princípios gerais são verdadeiros para namescopes XAML. No WPF, os namescopes de XAML são criados no elemento raiz de uma página XAML quando a página é carregada. Cada nome especificado na página XAML, começando na raiz da página, é adicionado a um namescopes de XAML pertinente.

No WPF XAML, os elementos que são elementos raiz comuns (como Page, e Window) sempre controlam um namescope XAML. Se um elemento como FrameworkElement ou FrameworkContentElement for o elemento raiz da página na marcação, um processador XAML adicionará uma Page raiz implicitamente para que o Page possa fornecer um namescope XAML em funcionamento.

Observação

As ações de compilação do WPF criam um namescope XAML para uma produção XAML mesmo se nenhum Name atributo ou x:Name estiver definido em qualquer elemento na marcação XAML.

Se você tentar usar o mesmo nome duas vezes em qualquer namescope de XAML, uma exceção será gerada. Para o XAML do WPF que tem code-behind e faz parte de um aplicativo compilado, a exceção é gerada em tempo de compilação por ações de compilação do WPF, ao criar a classe gerada para a página durante a compilação de marcação inicial. Para o XAML que não é compilado por marcação por qualquer ação de build, as exceções relacionadas a problemas de namescopes de XAML podem ser geradas quando o XAML é carregado. Os designers de XAML também podem prever problemas de namescope de XAML em tempo de design.

Adicionando objetos a árvores de objetos de runtime

O momento em que o XAML é analisado representa o momento em que um namescope de XAML do WPF é criado e definido. Se você adicionar um objeto a uma árvore de objetos em um ponto no tempo após o momento em que o XAML que produziu a árvore foi analisado, um valor Name ou x:Name no novo objeto não atualizará automaticamente as informações em um namescope de XAML. Para adicionar um nome para um objeto a um namescope XAML do WPF depois que o XAML for carregado, você deve chamar a implementação apropriada de no objeto que define o namescope XAML, que normalmente é a raiz da RegisterName página XAML. Se o nome não estiver registrado, o objeto adicionado não poderá ser referenciado pelo nome por meio de métodos como FindName, e você não poderá usar esse nome para direcionamento de animação.

O cenário mais comum para desenvolvedores de aplicativos é que você usará RegisterName para registrar nomes no namescope XAML na raiz atual da página. RegisterName faz parte de um cenário importante para storyboards que direcionam objetos para animações. Para obter mais informações, consulte Visão geral de storyboards.

Se você chamar RegisterName um objeto diferente do objeto que define o namescope XAML, o nome ainda será registrado no namescope XAML no qual o objeto de chamada é mantido, como se você tivesse chamado RegisterName o objeto de definição namescope XAML.

Namescopes de XAML no código

Você pode criar e usar namescopes de XAML no código. As APIs e os conceitos envolvidos na criação do namescope XAML são os mesmos mesmo para um uso de código puro, porque o processador XAML para WPF usa essas APIs e conceitos quando processa o próprio XAML. Os conceitos e a API existem principalmente para que seja possível encontrar objetos por nome em uma árvore de objeto que é normalmente definida, parcialmente ou totalmente, em XAML.

Para aplicativos criados programaticamente, e não a partir de XAML carregado, o objeto que define um namescope XAML deve implementar INameScope, ou ser uma FrameworkElement classe ou FrameworkContentElement derivada, para dar suporte à criação de um namescope XAML em suas instâncias.

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

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

Para obter um exemplo de uso de APIs de namescope de XAML no código, consulte Definir um escopo de nome.

Namescopes de XAML em estilos e modelos

Estilos e modelos no WPF fornecem a capacidade de reutilizar e reaplicar conteúdo de forma direta. No entanto, os estilos e modelos também podem incluir elementos com nomes XAML definidos no nível do modelo. Esse mesmo modelo pode ser usado várias vezes em uma página. Por esse motivo, os estilos e modelos definem seus próprios namescopes de XAML, independente do local, em uma árvore de objetos, em que o estilo ou o modelo é aplicado.

Considere o seguinte exemplo:

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

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

Os estilos também definem seus próprios namescopes de XAML, principalmente para que as partes de storyboards possam ter nomes específicos atribuídos. Esses nomes habilitam comportamentos específicos de controle que se destinarão a elementos desse nome, mesmo que o modelo tenha sido redefinido como parte da personalização do controle.

Devido aos namescopes de XAML separados, encontrar elementos nomeados em um modelo é mais desafiador que localizar um elemento nomeado que não faz parte do modelo em uma página. Primeiro, você precisa determinar o modelo aplicado, obtendo o Template valor da propriedade do controle onde o modelo é aplicado. Em seguida, você chama a versão do 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 determinado elemento nomeado em um modelo aplicado é o destino de um comportamento definido pelo próprio controle, você pode usar o GetTemplateChild método do código de implementação do controle. O GetTemplateChild método é protegido, portanto, somente o autor do controle tem acesso a ele.

Se você estiver trabalhando em um modelo e precisar acessar o namescope XAML onde o modelo é aplicado, obtenha o valor de TemplatedParente chame FindName lá. Um exemplo de trabalho dentro do modelo seria se você estivesse escrevendo a implementação do manipulador de eventos em que o evento será acionado de um elemento em um modelo aplicado.

FrameworkElement tem FindName, RegisterName e UnregisterName métodos. Se o objeto em que você chama esses métodos é proprietário de um namescope de XAML, os métodos chamam nos métodos do namescope de XAML relevante. Caso contrário, o elemento pai é verificado para ver se ele é proprietário de um namescope de XAML e esse processo continua recursivamente até que seja encontrado um namescope de XAML (devido ao comportamento do processador de XAML, é garantido que haverá um namescope de XAML na raiz). FrameworkContentElement tem comportamentos análogos, com a exceção de que nenhum deles FrameworkContentElement jamais possuirá um namescope XAML. Os métodos existem para que as chamadas possam ser encaminhadas eventualmente para FrameworkContentElement um FrameworkElement elemento pai.

SetNameScope é usado para mapear um novo namescope XAML para um objeto existente. Você pode chamar SetNameScope mais de uma vez para redefinir ou limpar o namescope XAML, mas esse não é um uso comum. Além disso, GetNameScope normalmente não é usado a partir do código.

Implementações de namescope de XAML

As seguintes classes são implementadas INameScope diretamente:

ResourceDictionary não usa nomes XAML ou namescopes; ele usa chaves em vez disso, porque é uma implementação de dicionário. O único motivo que implementa INameScope é para que ele possa gerar exceções ao código do usuário que ajudam a esclarecer a distinção entre um namescope XAML verdadeiro e como um manipula chaves, e também para garantir que ResourceDictionary os namescopes XAML não sejam aplicados a um ResourceDictionaryResourceDictionary por elementos pai.

FrameworkTemplate e Style implementar INameScope através de definições explícitas de interface. As implementações explícitas permitem que esses namescopes XAML se comportem convencionalmente quando são acessados por meio da INameScope interface, que é como os namescopes XAML são comunicados pelos processos internos do WPF. Mas as definições de interface explícitas não fazem parte da superfície de API convencional de FrameworkTemplate e , porque você raramente precisa chamar os INameScope métodos diretamente eStyle, em FrameworkTemplate vez disso, usaria outra API, como GetTemplateChildStyle.

As classes a seguir definem seu próprio namescope XAML, usando a System.Windows.NameScope classe auxiliar e conectando-se à implementação namescope XAML por meio da NameScope.NameScope propriedade anexada:

Confira também