Partilhar via


Visão geral de eventos e eventos roteados

APIs importantes

Descrevemos o conceito de programação de eventos em um aplicativo do Windows Runtime ao usar XAML para sua definição de interface do usuário. Você pode atribuir manipuladores para eventos como parte das declarações para elementos de interface do usuário no XAML ou pode adicionar os manipuladores no código. O Windows Runtime dá suporte a eventos roteado: determinados eventos de entrada e eventos de dados podem ser manipulados por objetos além do objeto que disparou o evento. Eventos roteados são úteis quando você define templates de controle, ou usa páginas ou contêineres de layout.

Eventos como um 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ê cria um aplicativo WinUI (ou UWP), a interface do usuário é definida em XAML (linguagem de marcação). 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 é conhecido como code-behind ou o arquivo code-behind. Nas exibições da solução do Microsoft Visual Studio, essa relação é mostrada graficamente, com o arquivo code-behind sendo um arquivo dependente e aninhado em comparação com a página XAML à qual se refere.

Button.Click: uma introdução aos eventos e ao 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 que 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 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 associar manipuladores de eventos a elementos individuais da interface do usuário ao mesmo tempo em que define todos os outros atributos XAML que estabelecem seus valores de propriedade.

Para conectar os eventos no XAML, especifique o nome em forma de cadeia de caracteres do método de manipulador que você já definiu ou definirá posteriormente em seu code-behind. Por exemplo, esse XAML define um objeto Button com outras propriedades (atributo x:Name, Content) atribuídas como atributos e conecta um manipulador para o evento Click do botão fazendo referência a um método chamado ShowUpdatesButton_Click:

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

Dica

Vinculação de eventos é 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 procedurais, o registro de eventos é um código "AddHandler" implícito ou explícito que nomeia tanto o evento quanto o método e geralmente envolve uma instância de objeto de destino. No XAML, o "AddHandler" é implícito, e a ligação de eventos consiste inteiramente em nomear o evento como o 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 você 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 por marcação, a etapa de compilação de marcação XAML na ação de build do IDE e a análise de XAML eventual quando o aplicativo carrega 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 delegado) para qualquer manipulador do evento Click . Por exemplo, esse código define o ShowUpdatesButton_Click manipulador.

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 ShowUpdatesButton_Click método é baseado no delegado RoutedEventHandler . Você saberia que esse é o delegado a ser usado porque você verá esse delegado 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 de manipulador enquanto você está editando 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 nome x:do elemento (ou nome do tipo), no nome do evento e em um sufixo numérico. Em seguida, você pode clicar com o botão direito do mouse no nome do manipulador de eventos selecionado e clicar em Navegar para o Manipulador de Eventos. Isso navegará 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 para a página XAML. O manipulador de eventos já tem a assinatura correta, incluindo o parâmetro remetente e a classe de dados de evento que o evento usa. Além disso, se um método de manipulador com a assinatura correta já existir em seu code-behind, o nome desse método será exibido na lista suspensa de preenchimento automático junto com a opção <Novo Manipulador> de Eventos. Você também pode pressionar a tecla Tab como um atalho em vez de clicar nos itens de lista do IntelliSense.

Definindo um manipulador de eventos

Para objetos que são elementos de interface do usuário e declarados em XAML, o código do manipulador de eventos é definido na classe parcial que serve como o code-behind para uma página XAML. Manipuladores de eventos são métodos que você escreve como parte da classe parcial associada ao seu XAML. Esses manipuladores de eventos são baseados nos delegados que um evento específico 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 finalmente 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 um membro de classe privada. As ações de compilação para um projeto C++ cuidam da geração de código, que oferece suporte ao sistema de tipos XAML e ao modelo code-behind para C++.

O parâmetro do remetente 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 é invocado. O primeiro valor desse tipo é o remetente, que é uma referência ao objeto em que o manipulador está anexado. O parâmetro de remetente é digitado como o tipo de objeto base. Uma técnica comum é a conversão de sender para um tipo mais preciso. Essa técnica será útil se você espera verificar ou alterar o estado no próprio objeto remetente . Com base no design do seu próprio aplicativo, geralmente você conhece um tipo seguro para o qual o sender é convertido, com base no local onde o manipulador está anexado ou outras especificidades de design.

O segundo valor são os dados de evento, que geralmente aparecem em definições de sintaxe como o parâmetro e (ou args). Você pode descobrir quais propriedades para dados de evento estão disponíveis examinando o parâmetro e do delegado atribuído para o evento específico que você está tratando e, em seguida, usando o IntelliSense ou o 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 é especialmente verdadeiro para os eventos de entrada. Em eventos de ponteiro, a posição do ponteiro no momento em que o evento ocorreu pode ter importância. Para eventos de teclado, todas as teclas 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 como lidar com eventos de entrada, consulte interações de teclado e entrada do ponteiro Handle. 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 e teclas modificadoras e códigos de chave de plataforma para eventos de teclado.

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

Em alguns casos, você desejará usar APIs que usam 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. Eles precisam ser chamados dentro de um escopo assíncrono/passível de espera, e o compilador 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, o manipulador de eventos tem permissão para fazer chamadas assíncronas/aguardadas.

Adicionando manipuladores de eventos no código

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, incluindo objetos que não são utilizáveis no XAML, você pode usar a sintaxe específica do idioma para adicionar manipuladores de eventos.

Em C#, a sintaxe é usar o += operador. Registre o manipulador referenciando o nome do método manipulador de eventos à direita do operador.

Se você usar o 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 um esboço XAML da estrutura da página e 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 verborágica. Em 2005, o C# adicionou um recurso chamado inferência de delegado, que permite que um compilador infera a nova instância delegada e habilite a sintaxe anterior e 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 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 é paralelizar 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 em tempo de carga 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 Nome / 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 tratamento de instância em vez da palavra-chave Handles . Isso ocorre porque estabelecer a fiação do manipulador de eventos no XAML faz parte do fluxo de trabalho típico do designer-desenvolvedor e a técnica de palavra-chave Handles é incompatível com a fiação dos manipuladores de eventos no XAML.

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

  • Não existe nenhuma inferência delegada, portanto, você deve usar ref new para a instância delegada.
  • O construtor delegado tem dois parâmetros e requer o objeto de destino como o primeiro parâmetro. Normalmente, você especifica isso.
  • O construtor delegado requer o endereço do método como o 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);

Removendo 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 de 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 os manipuladores de eventos explicitamente. Elas incluem:

  • Manipuladores que você adicionou para eventos estáticos, que não podem ser coletados de maneira convencional. Exemplos de eventos estáticos na API do Windows Runtime são os eventos das classes CompositionTarget e Clipboard .
  • Teste o código em que você deseja que o tempo de remoção do manipulador seja imediato ou o código em que você pode 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ção de página.

FrameworkElement.Unloaded ou Page.NavigatedFrom são possíveis gatilhos de evento que têm posições apropriadas no gerenciamento de estado e no tempo de vida do objeto, de modo que você possa usá-los para remover manipuladores para 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 é 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 o código posteriormente; no entanto, você também pode percorrer a árvore de objetos para localizar a referência de objeto necessária nos casos em que o objeto não tem Nome.

Se você precisar remover um manipulador de eventos no C++/CX, precisará de um token de inscrição, que deve ter recebido como 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 um atributo XAML porque o código gerado por C++/CX não salva um token.

Eventos roteados

O Windows Runtime dá suporte ao conceito de um evento roteado para um conjunto de eventos que estão 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 roteados:

Um evento roteado é um evento que é potencialmente passado (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 aproxima essa árvore, com a raiz dessa árvore sendo o elemento raiz em XAML. A árvore de objetos verdadeira pode variar um pouco do aninhamento do elemento XAML, pois a árvore de objetos não inclui recursos da linguagem XAML, como as marcas de elementos de propriedade. Você pode concebir o evento roteado como borbulhando de qualquer elemento filho do elemento de objeto XAML que dispara o evento, em direção ao elemento de 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 poderá continuar até que o elemento raiz seja atingido.

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

Quando um evento roteado percorre sua rota, todos os manipuladores de eventos anexados acessam uma instância compartilhada de dados do evento. Portanto, se qualquer um dos dados de evento for gravável por um manipulador, todas as alterações feitas nos dados do evento serão passadas para o próximo manipulador e poderão não representar mais os dados de evento 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 gera uma rota de evento, o remetente não é mais o mesmo objeto que o objeto de geração de eventos. Em vez disso, o remetente é o objeto ao qual o manipulador que está sendo invocado está vinculado.

Em alguns casos, o emitente não é interessante e, em vez disso, você está interessado em informações como em qual dos possíveis objetos filho o ponteiro está quando um evento de ponteiro é acionado, ou qual objeto em uma interface de usuário mais ampla 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 reporta o objeto original que disparou o evento, ao invés do objeto em que 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 derivada de um modelo de um controle. Por exemplo, se o usuário pairar o ponteiro sobre a borda de um Botão, para a maioria dos eventos de ponteiro, o OriginalSource será uma parte de modelo Border no Modelo, não o Botão em si.

Dica A propagação de eventos de entrada é especialmente útil se você estiver criando um controle modelado. 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 eventos 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 durante a instanciação.

A propriedade Handled

Várias classes de dados de evento para 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.

Definir a propriedade Handled como true influencia o comportamento do sistema de eventos. Quando Handled é true, o roteamento será interrompido para a maioria dos manipuladores de eventos; o evento não continua ao longo do percurso para notificar outros manipuladores anexados desse caso de evento específico. O que "tratado" significa no contexto do evento e como seu aplicativo responde a isso depende de você. Basicamente, Handled é um protocolo simples que permite que o código do aplicativo indique que uma ocorrência de um evento não precisa ser propagada para outros contêineres, pois sua lógica de aplicativo já lidou com o necessário. Por outro lado, porém, você precisa ter cuidado para não tratar de eventos que provavelmente devem ser propagados para que os comportamentos embutidos do sistema ou controle possam agir. Por exemplo, tratar eventos de baixo nível nos componentes de um controle de seleção pode ser prejudicial. O controle de seleção pode estar procurando eventos de entrada para saber que a seleção deve ser alterada.

Nem todos os eventos roteados podem anular o roteamento deste modo, e você pode perceber isso porque eles não terão uma propriedade Handled. Por exemplo, GotFocus e LostFocus fazem bolhas, mas eles sempre fazem bolhas 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 internamente o conceito Handled para eventos de entrada. Isso pode fazer parecer que um evento de entrada nunca ocorre, porque o código do usuário não pode lidar com ele. Por exemplo, a classe Button inclui lógica que manipula deliberadamente o evento de entrada geral PointerPressed. Ele faz isso porque os botões disparam um evento Click que é iniciado por entrada pressionada por ponteiro, bem como por outros modos de entrada, como manipulação de chaves como a tecla Enter que pode invocar o botão quando ele está focado. Para fins do design de classe de Button, o evento de entrada bruta é tratado conceitualmente e os consumidores de classe, como o código do usuário, podem interagir com o evento click relevante ao controle. Tópicos para classes de controle específicas na referência da API do Windows Runtime geralmente observam o comportamento de tratamento de eventos que a classe implementa. Em alguns casos, você pode alterar o comportamento substituindo os métodos OnEvent . Por exemplo, você pode alterar a forma como sua classe derivada de TextBox reage à entrada de chave substituindo Control.OnKeyDown.

Registrando manipuladores para eventos roteado já tratados

Anteriormente, dissemos que a configuração tratada como true impede que a maioria dos manipuladores seja chamada. 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 anterior na rota tenha definido Handled como true nos dados de evento compartilhados. Essa técnica será útil se um controle que você está usando tiver manipulado o evento em sua composição interna ou para lógica específica do controle. mas você ainda deseja responder a ela de uma instância de controle ou da interface do usuário do aplicativo. Mas use essa técnica com cuidado, pois ela pode contradizer a finalidade de Handled e possivelmente interromper as interações pretendidas de um controle.

Somente os eventos roteado que têm um identificador de evento roteado correspondente podem usar a técnica de manipulação de eventos AddHandler , pois o identificador é uma entrada necessária do método AddHandler . Consulte a documentação de referência do AddHandler para obter uma lista de eventos que têm identificadores de eventos roteados que estão disponíveis. Em sua maioria, esta é a mesma lista de eventos roteados que mostramos anteriormente. A exceção é que os dois últimos na 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

Determinados objetos participam de uma relação com a árvore visual primária que, conceitualmente, equivale a ter uma sobreposição sobre os visuais principais. Esses objetos não fazem parte das relações pai-filho habituais que conectam todos os elementos de árvore à raiz visual. Esse é o caso de qualquer Pop-up ou Dica de Ferramenta exibida. Se você quiser lidar com eventos roteados de um Pop-up ou ToolTip, coloque os manipuladores nos elementos específicos da interface do usuário dentro dos Pop-up ou ToolTip e não nos próprios elementos Pop-up ou ToolTip. Não confie no roteamento dentro de qualquer composição executada para conteúdo pop-up ou tooltip . Isso ocorre porque o roteamento de eventos para eventos funciona apenas ao longo da árvore visual principal. Um Pop-up ou ToolTip não é considerado um pai de elementos de interface do usuário subsidiários e nunca recebe o evento roteado, mesmo que esteja tentando usar algo como o plano de fundo padrão do Pop-up como a área de captura para eventos de entrada.

Eventos de entrada e teste de clique

Determinar se e onde um elemento é detectável por mouse, toque e caneta na interface do usuário é chamado de teste de impacto. Para que um elemento possa ser a origem de ações de toque, bem como de eventos específicos de interação ou manipulação que são consequências de uma ação de toque, ele deve ser visível ao teste de toque para ser o gatilho 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 possam interagir com essa entrada. Há vários fatores que afetam o teste de colisão, mas você pode determinar se um elemento pode disparar eventos de entrada verificando sua propriedade IsHitTestVisible. Essa propriedade retornará true somente 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 não é nulo. Um valorbrush nulo resulta em transparência e invisibilidade de teste de clique. (Para tornar um elemento transparente, mas também testável por clique, use um pincel Transparente em vez de nulo.)

Observeque Plano de Fundo e Preenchimento não são definidos por UIElement e, em vez disso, são definidos por classes derivadas diferentes, como Controle e Forma. Mas as implicações dos pincéis que você usa para propriedades em primeiro plano e em segundo plano são as mesmas para eventos de teste de clique e entrada, não importa qual subclasse implemente as propriedades.

  • Se o elemento for um controle, o valor da propriedade IsEnabled deve ser verdadeiro.
  • O elemento deve ter dimensões reais no layout. Um elemento onde ActualHeight e ActualWidth são iguais a 0 não emitirá eventos de entrada.

Alguns controles têm regras especiais para teste de colisão. Por exemplo, TextBlock não tem propriedade Background, mas ainda é testável para detecção de interação em toda a região de suas dimensões. Os controles Imagem e MediaElement são testáveis a interações dentro de suas dimensões retangulares 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 impacto porque a entrada pode ser manipulada pelo HTML hospedado e disparar eventos de script.

A maioria das classes de Painel e Borda não são testáveis por hit em seu próprio plano de fundo, mas ainda podem lidar com os eventos de entrada do usuário que são roteados a partir dos 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 serem testáveis por 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.

Comandando

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

Eventos personalizados no Windows Runtime

Para fins de definição de eventos personalizados, como você adiciona o evento e o que isso significa para seu design de classe é altamente dependente 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 padrão, desde que não esteja usando acessadores personalizados (adicione/remove). Dicas adicionais:
  • Para C++/CX, consulte Eventos (C++/CX).
    • Use referências nomeadas mesmo para seus próprios usos de eventos personalizados. Não use lambda para eventos personalizados, ele pode criar uma referência circular.

Você não pode 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 definição de um controle personalizado. É um padrão comum ter uma propriedade de dependência que possui um retorno de chamada para mudança de propriedade e também definir um evento personalizado que é acionado por esse retorno de chamada em alguns ou em todos os casos. Os consumidores do seu controle não têm acesso ao retorno de chamada de alteração de 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.