Visão geral de eventos e eventos roteados

APIs importantes

Descreve o conceito de programação de eventos em um aplicativo do Windows Runtime quando você usa as extensões de componente C#, Visual Basic ou Visual C++ (C++/CX) como linguagem de programação e XAML para a definição da interface do usuário. Você pode atribuir manipuladores de eventos como parte das declarações para elementos da interface do usuário em XAML ou pode adicionar manipuladores no código. O Windows Runtime dá suporte a eventos roteados: determinados eventos de entrada e eventos de dados podem ser manipulados por outros objetos além do objeto que acionou o evento. Eventos roteados são úteis quando você define modelos de controle ou usa páginas ou contêineres de layout.

Eventos como conceito de programação

De modo geral, os conceitos de evento ao programar um aplicativo do Windows Runtime são semelhantes ao modelo de evento nas linguagens de programação mais populares. Se você já souber como trabalhar com eventos do Microsoft .NET ou C++, terá uma vantagem inicial. Mas você não precisa saber muito sobre conceitos de modelo de evento para executar algumas tarefas básicas, como anexar manipuladores.

Quando você usa C#, Visual Basic ou C++/CX como sua linguagem de programação, a interface do usuário é definida em marcação (XAML). Na sintaxe de marcação XAML, alguns dos princípios de conexão de eventos entre elementos de marcação e entidades de código de runtime são semelhantes a outras tecnologias da Web, como ASP.NET ou HTML5.

Observação O código que fornece a lógica de runtime para uma interface do usuário definida por XAML geralmente é chamado de code-behind ou arquivo code-behind. Nas exibições de solução do Microsoft Visual Studio, essa relação é mostrada graficamente, com o arquivo code-behind sendo um arquivo dependente e aninhado versus a página XAML à qual se refere.

Button.Click: uma introdução a eventos e XAML

Uma das tarefas de programação mais comuns para um aplicativo do Windows Runtime é capturar a entrada do usuário na interface do usuário. Por exemplo, sua interface do usuário pode ter um botão no qual o usuário deve clicar para enviar informações ou alterar o estado.

Você define a interface do usuário para seu aplicativo do Windows Runtime gerando o XAML. Esse XAML geralmente é a saída de uma superfície de design no Visual Studio. Você também pode escrever o XAML em um editor de texto sem formatação ou em um editor XAML de terceiros. Ao gerar esse XAML, você pode conectar manipuladores de eventos para elementos individuais da interface do usuário ao mesmo tempo em que define todos os outros atributos XAML que estabelecem valores de propriedade desse elemento da interface do usuário.

Para conectar os eventos no XAML, especifique o nome do formulário de sequência do método de manipulador que você já definiu ou definirá posteriormente em seu code-behind. Por exemplo, esse XAML define um objeto Botão com outras propriedades (x:Name attribute, Content) designadas como atributos e conecta um manipulador para o evento de Clique do botão fazendo referência a um método chamado ShowUpdatesButton_Click:

<Button x:Name="showUpdatesButton"
  Content="{Binding ShowUpdatesText}"
  Click="ShowUpdatesButton_Click"/>

DicaConexão de evento é um termo de programação. Ele se refere ao processo ou código pelo qual você indica que as ocorrências de um evento devem invocar um método de manipulador nomeado. Na maioria dos modelos de código de procedimento, a conexão de evento é um código "AddHandler" implícito ou explícito que nomeia o evento e o método e geralmente envolve uma instância de objeto de destino. No XAML, o "AddHandler" é implícito e a conexão de evento consiste inteiramente em nomear o evento como nome do atributo de um elemento de objeto e nomear o manipulador como o valor desse atributo.

Você escreve o manipulador real na linguagem de programação que está usando para todo o código e code-behind do seu aplicativo. Com o atributo Click="ShowUpdatesButton_Click", você criou um contrato que, quando o XAML é compilado e analisado com marcação, a etapa de compilação de marcação XAML na ação de compilação do IDE e a eventual análise XAML quando o aplicativo é carregado podem encontrar um método nomeado ShowUpdatesButton_Click como parte do código do aplicativo. ShowUpdatesButton_Click deve ser um método que implementa uma assinatura de método compatível (com base em um representante) para qualquer manipulador do evento de Click. Por exemplo, esse código define o manipulador ShowUpdatesButton_Click.

private void ShowUpdatesButton_Click (object sender, RoutedEventArgs e) 
{
    Button b = sender as Button;
    //more logic to do here...
}
Private Sub ShowUpdatesButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    '  more logic to do here...
End Sub
void winrt::MyNamespace::implementation::BlankPage::ShowUpdatesButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e)
{
    auto b{ sender.as<Windows::UI::Xaml::Controls::Button>() };
    // More logic to do here.
}
void MyNamespace::BlankPage::ShowUpdatesButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 
{
    Button^ b = (Button^) sender;
    //more logic to do here...
}

Neste exemplo, o método ShowUpdatesButton_Click se baseia no representante RoutedEventHandler. Você saberia que esse é o representante a ser usado, pois o verá nomeado na sintaxe do método Click.

Dica O Visual Studio fornece uma maneira conveniente de nomear o manipulador de eventos e definir o método do manipulador enquanto você edita o XAML. Quando você fornecer o nome do atributo do evento no editor de texto XAML, aguarde um momento até que uma lista do Microsoft IntelliSense seja exibida. Se você clicar em <Novo manipulador de eventos> na lista, o Microsoft Visual Studio sugerirá um nome de método com base no x:Name (ou nome do tipo) do elemento, o nome do evento e um sufixo numérico. Em seguida, clique com o botão direito do mouse no nome do manipulador de eventos selecionado e clique em Navegar para o manipulador de eventos. Essa opção fará a navegação diretamente para a definição do manipulador de eventos recém-inserida, conforme visto na exibição do editor de código do arquivo code-behind da página XAML. O manipulador de eventos já tem a assinatura correta, incluindo o parâmetro sender e a classe de dados que o evento usa. Além disso, se um método de manipulador com a assinatura correta já existir no code-behind, o nome desse método aparecerá na lista suspensa de preenchimento automático com a opção <Novo manipulador de eventos> . Você também pode pressionar a tecla Tab como atalho em vez de clicar nos itens de lista do IntelliSense.

Definição de manipuladores de eventos

Para objetos que são elementos da interface do usuário e declarados em XAML, o código do manipulador de eventos é definido na classe parcial que serve como code-behind para uma página XAML. Os manipuladores de eventos são métodos que você escreve como parte da classe parcial associada ao XAML. Esses manipuladores de eventos se baseiam nos representantes que um determinado evento usa. Seus métodos de manipulador de eventos podem ser públicos ou privados. O acesso privado funciona porque o manipulador e a instância criados pelo XAML são, em última análise, unidos pela geração de código. Em geral, recomendamos que você torne seus métodos de manipulador de eventos privados na classe.

Observação Os manipuladores de eventos para C++ não são definidos em classes parciais; eles são declarados no cabeçalho como membro de classe privada. As ações de build para um projeto C++ cuidam da geração de código que oferece suporte ao sistema de tipo XAML e ao modelo code-behind para C++.

O parâmetro sender e os dados do evento

O manipulador que você escreve para o evento pode acessar dois valores que estão disponíveis como entrada para cada caso em que o manipulador é chamado. O primeiro desses dois valores é sender, que é uma referência ao objeto ao qual o manipulador está anexado. O parâmetro sender é digitado como tipo de Objeto base. Uma técnica comum é transmitir sender para um tipo mais preciso. Essa técnica é útil quando você espera verificar ou alterar o estado no próprio objeto sender. Com base no próprio design do aplicativo, você normalmente conhece um tipo que seja seguro ao qual transmitir o parâmetro sender, com base no local onde o manipulador foi anexado ou em outras especificações do design.

O segundo valor são dados de evento, que geralmente aparecem em definições de sintaxe como o parâmetro e. Você pode descobrir quais propriedades para dados de evento estão disponíveis examinando o parâmetro e do representante atribuído para o evento específico que você está manipulando e, em seguida, usando IntelliSense ou Pesquisador de objetos no Visual Studio. Ou você pode usar a documentação de referência do Windows Runtime.

Para alguns eventos, os valores de propriedade específicos dos dados do evento são tão importantes quanto saber que o evento ocorreu. Isso vale especialmente para os eventos de entrada. Para eventos de ponteiro, a posição do ponteiro quando o evento ocorreu pode ser importante. Para eventos de teclado, todos os pressionamentos de tecla possíveis disparam um evento KeyDown e KeyUp. Para determinar qual tecla um usuário pressionou, você deve acessar o KeyRoutedEventArgs que está disponível para o manipulador de eventos. Para obter mais informações sobre a manipulação de eventos de entrada, consulte Interações por teclado e Manipular entrada de ponteiro. Eventos de entrada e cenários de entrada geralmente têm considerações adicionais que não são abordadas neste tópico, como captura de ponteiro para eventos de ponteiro, bem como teclas modificadoras e códigos de tecla da plataforma para eventos de teclado.

Manipuladores de eventos que usam o padrão assíncrono

Em alguns casos, convém usar APIs que utilizam um padrão assíncrono em um manipulador de eventos. Por exemplo, você pode usar um Botão em um AppBar para exibir um seletor de arquivos e interagir com ele. No entanto, muitas das APIs do seletor de arquivos são assíncronas. Elas precisam ser chamadas dentro de um escopo assíncrono/aguardado, e o compilador vai impor isso. Portanto, o que você pode fazer é adicionar a palavra-chave async ao manipulador de eventos, de modo que o manipulador agora seja asyncvoid. Agora seu manipulador de eventos tem permissão para fazer chamadas assíncronas/aguardadas.

Para obter um exemplo de manipulação de eventos de interação do usuário usando o padrão assíncrono, consulte Acesso a arquivos e seletores (parte da série Criar seu primeiro aplicativo do Windows Runtime em C# ou Visual Basic). Consulte também (Chamar APIs assíncronas em C).

Adição de manipuladores de eventos no código

O XAML não é a única maneira de atribuir um manipulador de eventos a um objeto. Para adicionar manipuladores de eventos a qualquer objeto específico no código, inclusive a objetos que não são utilizáveis em XAML, você pode usar a sintaxe específica da linguagem para adicionar manipuladores de eventos.

Em C#, a sintaxe é usar o operador +=. Você registra o manipulador fazendo referência ao nome do método do manipulador de eventos no lado direito do operador.

Se você usar código para adicionar manipuladores de eventos a objetos que aparecem na interface do usuário em tempo de execução, uma prática comum é adicionar esses manipuladores em resposta a um evento de tempo de vida do objeto ou retorno de chamada, como Loaded ou OnApplyTemplate, para que os manipuladores de eventos no objeto relevante estejam prontos para eventos iniciados pelo usuário em tempo de execução. Este exemplo mostra uma estrutura do código XAML da estrutura da página e, em seguida, fornece a sintaxe da linguagem C# para adicionar um manipulador de eventos a um objeto.

<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
  <StackPanel>
    <TextBlock Name="textBlock1">Put the pointer over this text</TextBlock>
...
  </StackPanel>
</Grid>
void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += textBlock1_PointerEntered;
    textBlock1.PointerExited += textBlock1_PointerExited;
}

Observação Existe uma sintaxe mais detalhada. Em 2005, a C# adicionou um recurso chamado inferência delegada, que permite que um compilador infira a nova instância delegada e habilita a sintaxe anterior mais simples. A sintaxe detalhada é funcionalmente idêntica ao exemplo anterior, mas cria explicitamente uma nova instância delegada antes de registrá-la, não aproveitando assim a inferência delegada. Essa sintaxe explícita é menos comum, mas você ainda pode vê-la em alguns exemplos de código.

void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += new PointerEventHandler(textBlock1_PointerEntered);
    textBlock1.PointerExited += new MouseEventHandler(textBlock1_PointerExited);
}

Há duas possibilidades para a sintaxe do Visual Basic. Uma delas é fazer um paralelo com a sintaxe C# e anexar manipuladores diretamente às instâncias. Isso requer a palavra-chave AddHandler e também o operador AddressOf que desreferencia o nome do método do manipulador.

A outra opção para a sintaxe do Visual Basic é usar a palavra-chave Handles em manipuladores de eventos. Essa técnica é apropriada para casos em que se espera que os manipuladores existam em objetos no tempo de carregamento e persistam durante todo o tempo de vida do objeto. O uso de Handles em um objeto definido em XAML requer que você forneça um Name / x:Name. Esse nome se torna o qualificador de instância necessário para a parte Instance.Event da sintaxe Handles. Nesse caso, você não precisa de um manipulador de eventos baseado no tempo de vida do objeto para iniciar a anexação dos outros manipuladores de eventos; as conexões Handles são criadas quando você compila sua página XAML.

Private Sub textBlock1_PointerEntered(ByVal sender As Object, ByVal e As PointerRoutedEventArgs) Handles textBlock1.PointerEntered
' ...
End Sub

Observação O Visual Studio e sua superfície de design XAML geralmente promovem a técnica de manipulação de instâncias em vez da palavra-chave Handles. Isso ocorre porque estabelecer a conexão do manipulador de eventos em XAML faz parte do fluxo de trabalho típico do designer-desenvolvedor e a técnica da palavra-chave Handles é incompatível com a conexão dos manipuladores de eventos em XAML.

Em C++/CX, você também usa a sintaxe +=, mas há diferenças em relação ao formulário C# básico:

  • Não existe inferência delegada, de modo que você deve usar ref new para a instância delegada.
  • O construtor delegado tem dois parâmetros e exige o objeto de destino como primeiro parâmetro. Normalmente, você especifica isso.
  • O construtor delegado exige o endereço do método como segundo parâmetro, de modo que o operador de referência & precede o nome do método.
textBlock1().PointerEntered({this, &MainPage::TextBlock1_PointerEntered });
textBlock1->PointerEntered += 
ref new PointerEventHandler(this, &BlankPage::textBlock1_PointerEntered);

Remoção de manipuladores de eventos no código

Normalmente, não é necessário remover manipuladores de eventos no código, mesmo que você os tenha adicionado no código. O comportamento do tempo de vida do objeto para a maioria dos objetos do Windows Runtime, como páginas e controles, destruirá os objetos quando eles forem desconectados da Janela principal e de sua árvore visual, e todas as referências delegadas também serão destruídas. O .NET faz isso por meio da coleta de lixo e o Windows Runtime com C++/CX usa referências fracas por padrão.

Há alguns casos raros em que você deseja remover manipuladores de eventos explicitamente. Estão incluídos:

  • Manipuladores que você adicionou para eventos estáticos, que não podem ser coletados de forma convencional. Exemplos de eventos estáticos na API do Windows Runtime são os eventos das classes CompositionTarget e Clipboard.
  • Código de teste em que você deseja que o tempo de remoção do manipulador seja imediato ou código em que você deve trocar manipuladores de eventos antigos/novos por um evento em tempo de execução.
  • A implementação de um acessador de remoção personalizado.
  • Eventos estáticos personalizados.
  • Manipuladores para navegações de página.

FrameworkElement.Unloaded ou Page.NavigatedFrom são possíveis gatilhos de eventos que têm posições apropriadas no gerenciamento de estado e no tempo de vida do objeto, de modo que você pode usá-los para remover manipuladores de outros eventos.

Por exemplo, você pode remover um manipulador de eventos chamado textBlock1_PointerEntered do objeto de destino textBlock1 usando esse código.

textBlock1.PointerEntered -= textBlock1_PointerEntered;
RemoveHandler textBlock1.PointerEntered, AddressOf textBlock1_PointerEntered

Você também pode remover manipuladores para casos em que o evento foi adicionado por meio de um atributo XAML, o que significa que o manipulador foi adicionado no código gerado. Isso será mais fácil de fazer se você forneceu um valor Name para o elemento em que o manipulador foi anexado, porque isso fornece uma referência de objeto para código posteriormente; no entanto, você também pode percorrer a árvore de objetos para encontrar a referência de objeto necessária nos casos em que o objeto não tem o valor Name.

Caso precise remover um manipulador de eventos em C++/CX, será necessário um token de registro, que você deveria ter recebido do valor de retorno do registro do manipulador de eventos +=. Isso ocorre porque o valor que você usa para o lado direito do cancelamento de registro -= na sintaxe C++/CX é o token, não o nome do método. Para C++/CX, você não pode remover manipuladores que foram adicionados como atributo XAML porque o código gerado em C++/CX não salva um token.

Eventos roteados

O Windows Runtime com C#, Microsoft Visual Basic ou C++/CX oferece suporte ao conceito de evento roteado para um conjunto de eventos presentes na maioria dos elementos da interface do usuário. Esses eventos são para cenários de entrada e interação do usuário e são implementados na classe base UIElement. Aqui está uma lista de eventos de entrada que são eventos roteados:

Um evento roteado é aquele potencialmente transmitido (roteado) de um objeto filho para cada um de seus objetos pai sucessivos em uma árvore de objetos. A estrutura XAML da interface do usuário se aproxima dessa árvore, com a raiz dessa árvore sendo o elemento raiz em XAML. A árvore de objetos verdadeira pode variar um pouco do aninhamento de elementos XAML, porque ela não inclui recursos de linguagem XAML, como tags de elemento de propriedade. Você pode conceber o evento roteado como propagação de qualquer elemento filho do elemento de objeto XAML que dispara o evento, em direção ao elemento do objeto pai que o contém. O evento e seus dados de evento podem ser manipulados em vários objetos ao longo da rota do evento. Se nenhum elemento tiver manipuladores, a rota potencialmente continuará até que o elemento raiz seja alcançado.

Se você conhece tecnologias da Web, como HTML dinâmico (DHTML) ou HTML5, talvez já esteja familiarizado com o conceito de evento de propagação.

Quando um evento roteado se propaga por sua rota de evento, todos os manipuladores de eventos anexados acessam uma instância compartilhada de dados de evento. Portanto, se qualquer um dos dados de evento for gravável por um manipulador, quaisquer alterações feitas nos dados de evento serão transmitidas para o próximo manipulador e não poderão mais representar os dados originais do evento. Quando um evento tiver um comportamento de evento roteado, a documentação de referência incluirá comentários ou outras notações sobre o comportamento roteado.

A propriedade OriginalSource de RoutedEventArgs

Quando um evento se propaga por uma rota de eventos, o objeto sender não é mais o mesmo da geração de eventos. Em vez disso, sender é o objeto em que o manipulador que está sendo invocado está anexado.

Em alguns casos, sender não é interessante; em vez disso, você está interessado em saber sobre quais dos possíveis objetos filho o ponteiro estava quando um evento de ponteiro foi acionado ou qual objeto em uma interface maior do usuário manteve o foco quando um usuário pressionou uma tecla do teclado. Para esses casos, você pode usar o valor da propriedade OriginalSource. Em todos os pontos da rota, OriginalSource relata o objeto original que disparou o evento, em vez do objeto ao qual o manipulador está anexado. No entanto, para eventos de entrada UIElement, esse objeto original geralmente é um objeto que não é imediatamente visível no XAML de definição de interface do usuário no nível da página. Em vez disso, esse objeto de origem original pode ser uma parte modelada de um controle. Por exemplo, se o usuário passar o mouse sobre a borda de um Botão, na maioria dos eventos de ponteiro, o OriginalSource será um componente de modelo Borda no Modelo, não o Botão propriamente dito.

Dica A propagação de evento de entrada é especialmente útil quando você está criando um controle modelo. Qualquer controle que tenha um modelo pode ter um novo modelo aplicado por seu consumidor. O consumidor que está tentando recriar um modelo de trabalho pode eliminar involuntariamente algum tratamento de evento declarado no modelo padrão. Você ainda pode fornecer tratamento de evento no nível de controle anexando manipuladores como parte da substituição OnApplyTemplate na definição de classe. Em seguida, você pode capturar os eventos de entrada que se propagam até a raiz do controle na instanciação.

A propriedade Handled

Várias classes de dados de eventos roteados específicos contêm uma propriedade chamada Handled. Para obter exemplos, consulte PointerRoutedEventArgs.Handled, KeyRoutedEventArgs.Handled, DragEventArgs.Handled. Em todos os casos, Handled é uma propriedade booliana configurável.

A definição da propriedade Handled como true influencia o comportamento do sistema de eventos. Quando Handled é true, o roteamento é interrompido para a maioria dos manipuladores de eventos, e o evento não continua ao longo da rota para notificar outros manipuladores anexados sobre esse caso de evento específico. O que "handled" significa no contexto do evento e como seu aplicativo responde a ele depende de você. Basicamente, Handled é um protocolo simples que permite que o código do aplicativo declare que a ocorrência de um evento não precisa ser propagada para nenhum contêiner; a lógica do aplicativo se encarregou de tudo. Por outro lado, porém, você precisa ter cuidado para não tratar eventos que provavelmente devem se propagar para que os comportamentos internos do sistema ou de controle possam agir. Por exemplo, tratar eventos de nível inferior dentro das partes ou dos itens de um controle de seleção pode ser prejudicial. O controle de seleção pode estar procurando eventos de entrada para saber se a seleção deve ser alterada.

Nem todos os eventos roteados podem cancelar uma rota dessa maneira, e você pode dizer isso porque eles não terão uma propriedade Handled. Por exemplo, GotFocus e LostFocus realmente se propagam, mas nem sempre até a raiz, e suas classes de dados de evento não têm uma propriedade Handled que possa influenciar esse comportamento.

Manipuladores de eventos de entrada em controles

Controles específicos do Windows Runtime às vezes usam o conceito Handled para eventos de entrada internamente. Isso pode fazer parecer que um evento de entrada nunca ocorre, porque seu código de usuário não pode manipulá-lo. Por exemplo, a classe Button inclui a lógica que manipula deliberadamente o evento de entrada geral PointerPressed. Ela faz isso porque os botões disparam um evento de Click que é iniciado pela entrada do ponteiro pressionado, bem como por outros modos de entrada, como manipular teclas como a tecla Enter que pode invocar o botão quando ele é focado. Para fins do design de classe Button, o evento de dados brutos é conceitualmente manipulado e os consumidores de classe, como seu código de usuário, podem interagir com o evento de Click relevante para o controle. Os tópicos para classes de controle específicas na referência de API do Windows Runtime geralmente observam o comportamento de manipulação de eventos que a classe implementa. Em alguns casos, você pode alterar o comportamento substituindo os métodos OnEvent. Por exemplo, você pode alterar como sua classe derivada TextBox reage à entrada de tecla substituindo Control.OnKeyDown.

Registro de manipuladores para eventos roteados já manipulados

Anteriormente, dizíamos que a configuração de Handled como true impede a chamada da maioria dos manipuladores. Mas o método AddHandler fornece uma técnica em que você pode anexar um manipulador que é sempre invocado para a rota, mesmo que algum outro manipulador anteriormente na rota tenha definido Handled como true nos dados de evento compartilhados. Essa técnica será útil se um controle que você estiver usando tiver tratado o evento em sua composição interna ou para lógica específica de controle, mas você ainda deseja responder a ele de uma instância de controle ou da interface do usuário do aplicativo. Mas use essa técnica com cautela, porque ela pode contradizer o propósito de Handled e possivelmente desfazer as interações pretendidas de um controle.

Somente os eventos roteados que têm um identificador de evento roteado correspondente podem usar a técnica de manipulação de eventos AddHandler, porque o identificador é uma entrada obrigatória do método AddHandler. Consulte a documentação de referência para AddHandler para obter uma lista de eventos que têm identificadores de eventos roteados disponíveis. Na maioria das vezes, essa é a mesma lista de eventos roteados que mostramos anteriormente. A exceção é que os dois últimos da lista, GotFocus e LostFocus, não têm um identificador de evento roteado; portanto, você não pode usar AddHandler para eles.

Eventos roteados fora da árvore visual

Certos objetos participam de um relacionamento com a árvore visual primária que é conceitualmente como ter uma sobreposição dos visuais principais. Esses objetos não fazem parte dos relacionamentos pai-filho usuais que conectam todos os elementos de árvore à raiz visual. Esse é o caso de qualquer Pop-up ou Dica de ferramenta exibida. Se você quiser manipular eventos roteados de uma Pop-up ou de uma Dica de ferramenta, coloque os manipuladores em elementos específicos da interface do usuário que estejam na Pop-up ou na Dica de ferramenta e não nos próprios elementos de Pop-up ou Dica de ferramenta. Não confie no roteamento dentro de qualquer composição executada para conteúdo de Pop-up ou Dica de ferramenta. Isso ocorre porque o roteamento de eventos roteados só funciona ao longo da árvore visual principal. Uma Pop-up ou Dica de ferramenta não é considerada pai de elementos subsidiários de interface do usuário e nunca recebe o evento roteado, mesmo que esteja tentando usar algo como o plano de fundo padrão da Pop-up como área de captura para eventos de entrada.

Teste de clique e eventos de entrada

Determinar se e onde na interface do usuário um elemento é visível para entrada do mouse, toque e caneta é chamado de teste de clique. Para ações de toque e também para eventos específicos de interação ou manipulação que são consequências de uma ação de toque, um elemento deve ter o teste de clique visível para ser a origem do evento e disparar o evento associado à ação. Caso contrário, a ação passa pelo elemento para quaisquer elementos subjacentes ou elementos pai na árvore visual que poderiam interagir com essa entrada. Há vários fatores que afetam o teste de clique, mas você pode determinar se um elemento específico pode disparar eventos de entrada marcando a propriedade IsHitTestVisible. Essa propriedade só retornará true se o elemento atender a estes critérios:

  • O valor da propriedade Visibility do elemento é Visible.
  • O valor da propriedade Background ou Fill do elemento é null. Um valor nullBrush resulta em transparência e invisibilidade do teste de clique. (Para tornar um elemento transparente, mas também passível de teste de clique, use um pincel Transparente em vez de nulo.)

ObservaçãoPlano de fundo e Preenchimento não são definidos por UIElement; em vez disso, são definidos por diferentes classes derivadas, como Controle e Forma. Mas as implicações dos pincéis que você usa para propriedades de primeiro plano e plano de fundo são as mesmas para teste de clique e eventos de entrada, independentemente de qual subclasse implementa as propriedades.

  • Se o elemento for um controle, o valor da propriedade IsEnabled deverá ser true.
  • O elemento deve ter dimensões reais no layout. Um elemento em que ActualHeight e ActualWidth são 0 não vai disparar eventos de entrada.

Alguns controles têm regras especiais para testes de clique. Por exemplo, TextBlock não tem nenhuma propriedade Background, mas ainda tem teste de clique em toda a região de suas dimensões. Os controles Image e MediaElement podem ter teste de clique em suas dimensões de retângulo definidas, independentemente do conteúdo transparente, como o canal alfa no arquivo de origem de mídia que está sendo exibido. Os controles WebView têm um comportamento especial de teste de clique porque a entrada pode ser manipulada pelos eventos HTML e fire script hospedados.

A maioria das classes Panel e Border não tem teste de clique em seu próprio plano de fundo, mas ainda podem manipular os eventos de entrada do usuário que são roteados com base nos elementos que eles contêm.

Você pode determinar quais elementos estão localizados na mesma posição que um evento de entrada do usuário, independentemente de os elementos poderem ter ou não teste de clique. Para fazer isso, chame o método FindElementsInHostCoordinates. Como o nome indica, esse método localiza os elementos em um local relativo a um elemento host especificado. No entanto, transformações aplicadas e alterações de layout podem ajustar o sistema de coordenadas relativas de um elemento e, portanto, afetar quais elementos são encontrados em um determinado local.

Comando

Um número pequeno de elementos da interface do usuário oferece suporte a comando. O comando usa eventos roteados relacionados à entrada em sua implementação subjacente e permite o processamento da entrada da interface do usuário relacionada (uma determinada ação de ponteiro, uma tecla de aceleração específica) invocando um único manipulador de comando. Se o comando estiver disponível para um elemento da interface do usuário, considere usar suas APIs de comando em vez de quaisquer eventos de entrada discretos. Normalmente, você usa uma referência de Associação nas propriedades de uma classe que define o modelo de exibição de dados. As propriedades contêm comandos nomeados que implementam o padrão de comando ICommand específico da linguagem. Para obter mais informações, consulte ButtonBase.Command.

Eventos personalizados no Windows Runtime

Para fins de definição de eventos personalizados, a forma como você adiciona o evento e o que isso significa para o design de classe depende muito da linguagem de programação que você está usando.

  • Para C# e Visual Basic, você está definindo um evento CLR. Você pode usar o padrão de evento .NET predefinido, desde que não esteja usando acessadores personalizados (adicionar/remover). Dicas adicionais:
  • Para C++/CX, consulte Eventos (C++/CX).
    • Use referências nomeadas até mesmo para seus próprios usos de eventos personalizados. Não use o lambda para eventos personalizados; ele pode criar uma referência circular.

Não é possível declarar um evento roteado personalizado para o Windows Runtime; os eventos roteados são limitados ao conjunto que vem do Windows Runtime.

A definição de um evento personalizado geralmente é feita como parte do exercício de definir um controle personalizado. É um padrão comum ter uma propriedade de dependência que tenha um retorno de chamada alterado por propriedade e também definir um evento personalizado que é acionado pelo retorno de chamada da propriedade de dependência em alguns ou em todos os casos. Os consumidores do seu controle não têm acesso ao retorno de chamada alterado por propriedade que você definiu, mas ter um evento de notificação disponível é a próxima melhor coisa. Para obter mais informações, consulte Propriedades de dependência personalizadas.