Partilhar via


Visão geral sobre eventos roteados

Este tópico descreve o conceito de eventos roteados no Windows Presentation Foundation (WPF). O tópico define a terminologia de eventos roteados, descreve como eventos roteados são roteados através de uma árvore de elementos, faz um resumo de como se manipula eventos roteados e apresenta como criar seus próprios eventos roteados personalizados.

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

  • Pré-requisitos
  • O que é um evento roteado?
  • Estratégias de roteamento
  • Por que usar eventos roteados?
  • Adicionando e implementando um manipulador de eventos para um evento roteado
  • Manipuladores por classe
  • Eventos anexados no WPF
  • Nomes de eventos qualificados em XAML
  • Eventos de entrada no WPF
  • EventSetters e EventTriggers
  • Mais informações sobre eventos roteados
  • Tópicos relacionados

Pré-requisitos

Este tópico pressupõe que você tenha conhecimento básico do common language runtime (CLR) e de programação orientada a objetos, bem como do conceito de como os relacionamentos entre elementos WPF podem ser conceitualizados como uma árvore. Para que você siga os exemplos deste tópico, você também deve entender Extensible Application Markup Language (XAML) e saber como escrever aplicações ou páginas WPF básicas. Para obter mais informações, consulte Getting Started with Windows Presentation Foundation e XAML Overview.

O que é um evento roteado?

Você pode pensar sobre eventos roteados a partir de uma perspectiva funcional ou de implementação. Ambas as definições são apresentadas aqui, pois algumas pessoas acham uma das duas definições mais útil que a outra.

Definição funcional: Um evento roteado é um tipo de evento que pode chamar manipuladores em vários ouvintes em uma árvore, em vez de apenas no objeto que disparou o evento.

Definição de implementação: A evento roteado is a CLR qual é feito por uma ocorrência de eventos do RoutedEvent classe e processado pela Windows Presentation Foundation (WPF) sistema de eventos.

Um aplicativo WPF típico contém muitos elementos. Seja criados em código ou declarados em XAML, esses elementos existem em um relacionamento de árvore de elementos entre si. A rota do evento pode se mover em uma das duas direções, dependendo da definição do evento, mas geralmente a rota vai do elemento de origem e sobe como uma "bolha" através da árvore de elementos até que ele atinja a elemento raiz da árvore (geralmente uma página ou uma janela). Esse conceito de "bolha" pode ser familiar para você caso você tenha trabalhado com o modelo de objetos DHTML anteriormente.

Considere a seguinte árvore de elementos simples:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

Esta árvore de elementos produz algo parecido com o seguinte:

Botões Sim, Não e Cancelar

Nesta árvore de elementos simplificada, a fonte de um evento Click é um dos elementos Button, e seja qual for o Button clicado, este será o primeiro elemento que tem a oportunidade de tratar o evento. Mas se nenhum manipulador anexado ao Button age sobre o evento, em seguida, o evento sobe como uma bolha ao pai do Button na árvore de elementos, que é o StackPanel. Possivelmente, o evento sobe como bolha para Border e além, até a página raiz da árvore de elementos (não mostrada).

Em outras palavras, a rota de eventos para este evento Click é:

Button-->StackPanel-->Border-->...

Cenários de alto nível para eventos roteados

Este é um breve resumo dos cenários que motivaram o conceito de evento roteado, e por que um evento CLR típico não foi adequado para essas situações:

Controle de composição e encapsulamento: Vários controles de WPF ter um modelo de conteúdo rich. Por exemplo, você pode colocar uma imagem dentro de um Button, o que efetivamente estende a árvore visual do botão. No entanto, a imagem adicionada não deve interromper o comportamento do teste de colisão que faz com que um botão responda a uma Click em seu conteúdo, mesmo se o usuário clicar em pixels que tecnicamente fazem parte da imagem.

Manipulador singular anexo pontos: In Windows Forms, você teria de anexar o mesmo manipulador várias vezes a eventos de processo que podem ser aumentados de vários elementos. Eventos roteados permitem que você anexe esse manipulador somente uma vez, como foi mostrado no exemplo anterior, e use a lógica de tratamento para determinar de onde o evento veio, se necessário. Por exemplo, esse pode ser o manipulador para o XAML mostrado anteriormente:

private void CommonClickHandler(object sender, RoutedEventArgs e)
{
  FrameworkElement feSource = e.Source as FrameworkElement;
  switch (feSource.Name)
  {
    case "YesButton":
      // do something here ...
      break;
    case "NoButton":
      // do something ...
      break;
    case "CancelButton":
      // do something ...
      break;
  }
  e.Handled=true;
}

Tratamento de classe: Roteadas permitir eventos de um manipulador estático definido pela classe. Esse manipulador da classe tem a oportunidade de manipular um evento antes de qualquer manipulador anexado das instâncias possa fazê-lo.

Fazendo referência a um evento sem reflexão: Algumas técnicas de código e marcação exigem uma maneira de identificar um evento específico. Um evento roteado cria um campo RoutedEvent como identificador, o que fornece uma técnica robusta de identificação de eventos que não exije reflexão estática ou em tempo de execução.

Como eventos roteados são implementados

Um evento roteado é um evento do CLR que é suportado por uma instância da classe RoutedEvent e registrado com o sistema de eventos do WPF. A instância de RoutedEvent obtida no registro normalmente é mantida como um campo public static readonly membro da classe que registra e, portanto, "proprietária" do evento roteado. A conexão com o evento CLR de mesmo nome (que às vezes é chamado de evento envolvente - "wrapper") é realizada pela sobrescrita das implementações de add e remove no evento do CLR. Normalmente, add e remove são deixados como um padrão implícito que usa a sintaxe apropriada de eventos específica da linguagem para adicionar e remover os manipuladores daquele evento. O mecanismo de suporte e conexão de eventos roteados é conceitualmente semelhante a como uma propriedade de dependência é uma propriedade do CLR que é suportada pela classe DependencyProperty e registrada com o sistema de propriedades do WPF.

O exemplo a seguir mostra a declaração de um evento roteado Tap personalizado, incluindo o registro e a exposição do campo identificador do RoutedEvent e as implementações de add e remove para o evento Tap do CLR.

Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))

' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
    AddHandler(ByVal value As RoutedEventHandler)
        Me.AddHandler(TapEvent, value)
    End AddHandler

    RemoveHandler(ByVal value As RoutedEventHandler)
        Me.RemoveHandler(TapEvent, value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.RaiseEvent(e)
    End RaiseEvent
End Event

Manipuladores de eventos roteados e XAML

Para adicionar um manipulador para um evento utilizando XAML você declara o nome do evento como um atributo do elemento que é ouvinte de eventos. O valor do atributo é o nome do seu método manipulador implementado, que deve existir na classe parcial no arquivo de código.

<Button Click="b1SetColor">button</Button>

A sintaxe XAML para adicionar manipuladores de eventos padrão do CLR é a mesma usada para adicionar manipuladores de eventos roteados, pois você está de fato adicionando manipuladores ao wrapper de eventos do CLR, que tem uma implementação de eventos roteados por baixo. Para obter mais informações sobre como adicionar manipuladores de evento em XAML, consulte XAML Overview.

Estratégias de roteamento

Eventos roteados usam uma de três estratégias de roteamento:

  • Propagação: Manipuladores de eventos na fonte do evento são invocados. O evento roteado, em seguida, é roteado para sucessivos elementos pai até alcançar a raiz da árvore de elementos. A maioria dos eventos roteados usam a estratégia de roteamento bolha. Eventos roteados bolha geralmente são usados para informar alterações de entrada ou de estado de diferentes controles ou outros elementos de interface do usuário.

  • Direto: Somente o elemento de fonte propriamente dito é terá a oportunidade de chamar manipuladores de resposta. Isso é análogo ao "roteamento" que o Windows Forms usa para eventos. No entanto, diferentemente de um evento CLR padrão, eventos roteados diretos suportam tratamento por classe (tratamento por classe é explicado em uma seção futura) e podem ser usadoa por EventSetter e EventTrigger.

  • Encapsulamento: Inicialmente, manipuladores de eventos na raiz da árvore de elemento são invocados. O evento roteado, em seguida, passa por uma rota através de sucessivos elementos filhos, em direção ao elemento nó que é a fonte do evento roteado (o elemento que lançou o evento roteado). Eventos roteados por tunelamento são frequentemente usados ou tratados como parte da composição de um controle, de tal modo que eventos de partes da composição possam ser deliberadamente suprimidos ou substituídos por eventos que são específicos ao controle completo. Eventos de entrada fornecidos no WPF geralmente vêm implementados como um par tunelamento/bolha. Eventos por tunelamento são também às vezes chamados de eventos de inspeção prévia ("preview"), por causa de uma convenção de nomeclatura que é usada para os pares.

Por que usar eventos roteados?

Como um desenvolvedor de aplicativos, você nem sempre precisará saber ou se preocupar se o evento que você está tratando é implementado como um evento roteado. Eventos roteados têm um comportamento especial, mas esse comportamento é praticamente invisível se você está tratando um evento no elemento onde ele foi gerado.

Onde os eventos roteados tornam-se eficientes é se você usar qualquer um dos cenários sugeridos: Definindo manipuladores comuns em uma raiz comum, composição seu próprio controle ou definir sua própria classe de controle personalizado.

Ouvintes de eventos roteados e fontes de eventos roteados não precisam compartilhar um evento em comum em sua hierarquia. Qualquer UIElement ou ContentElement pode ser ouvinte de eventos para qualquer evento roteado. Portanto, você pode usar o conjunto completo de eventos roteados disponíveis em cada API disponível como uma interface conceitual na qual diferentes elementos do aplicativo podem trocar informações de eventos. Esse conceito de "interface" para eventos roteados é aplicável principalmente para eventos de entrada.

Eventos roteados também podem ser usados para se comunicar através da árvore de elementos, pois os dados do evento são perpetuados em cada elemento da rota. Um elemento poderia modificar algo nos dados do evento, e essa alteração estaria disponível para o próximo elemento da rota.

Além do aspecto de roteamento, existem dois outros motivos pelos quais um dado evento do WPF poderia ser implementado como um evento roteado em vez de um evento padrão do CLR. Se você estiver implementando seus próprios eventos, você também pode considerar esses princípios:

  • Determinados recursos de templating e estilo do WPF, como EventSetter e EventTrigger, exigem que o evento referenciado seja um evento roteado. Este é o cenário de identificadores de evento mencionado anteriormente.

  • Eventos roteados suportam um mecanismo de tratamento por classe pelo qual a classe pode especificar métodos estáticos que terão a oportunidade de tratar os eventos roteados antes que qualquer manipulador registrado por instância possa acessá-los. Isso é muito útil no projeto de controles, pois sua classe pode impor comportamentos de classe orientados a eventos que não podem ser acidentalmente suprimidos ao tratar um evento em uma instância.

Cada uma das considerações acima é discutida em uma seção separada neste tópico.

Adicionando e implementando um manipulador de eventos para um evento roteado

Para adicionar um manipulador de eventos em XAML, você simplesmente adiciona o nome do evento a um elemento como atributo e define o valor do atributo como o nome do manipulador de eventos que implementa um delegado apropriado, como no exemplo a seguir.

<Button Click="b1SetColor">button</Button>

b1SetColor é o nome do manipulador implementado que contém o código que manipula o Click evento. b1SetColor deve ter a mesma assinatura que o RoutedEventHandler delegado, que é o delegado manipulador de eventos para o Click evento. O primeiro parâmetro de todos os delegados manipuladores de eventos roteados especifica o elemento ao qual o manipulador de eventos é adicionado, e o segundo parâmetro especifica os dados para o evento.

void b1SetColor(object sender, RoutedEventArgs args)
{
  //logic to handle the Click event


...


}

RoutedEventHandler é o delegado manipulador de eventos roteados básico. Para eventos roteados que são especializados para certos controles ou cenários, os delegados a ser usados para os manipuladores de eventos roteados também podem se tornar mais especializados, de modo que eles possam transmitir dados especializados de eventos. Por exemplo, em um cenário comum de entrada, você pode tratar um evento roteado DragEnter . O manipulador deve implementar o delegado DragEventHandler. Usando o delegado mais específico, você pode processar o DragEventArgs no manipulador e ler a propriedade Data, que contém a carga da área de transferência da operação de arrastar.

Para obter um exemplo completo de como adicionar um manipulador de eventos a um elemento usando XAML, consulte Como: Handle a Routed Event.

Adicionar um manipulador para um evento roteado em um aplicativo criado em código é simples. Os manipuladores de eventos roteados sempre podem ser adicionados por meio de um método auxiliar AddHandler (que é o mesmo método que o suporte existente chama para add). No entanto, eventos roteados do WPF existentes geralmente têm implementações de suporte da lógica de add e remove que permitem que os manipuladores de eventos roteados sejam adicionados por uma sintaxe de eventos específica da linguagem, o que é uma sintaxe mais intuitiva que o método auxiliar. Este é um exemplo de uso do método auxiliar:

void MakeButton()
 {
     Button b2 = new Button();
     b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
 }
 void Onb2Click(object sender, RoutedEventArgs e)
 {
     //logic to handle the Click event     
 }

O exemplo a seguir mostra a sintaxe de operadores de C# (Visual Basic tem uma sintaxe de operadores ligeiramente diferente devido a seu tratamento de referências):

void MakeButton2()
{
  Button b2 = new Button();
  b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
  //logic to handle the Click event     
}

Para obter um exemplo de como adicionar um manipulador de eventos em código, consulte Como: Adicionar um manipulador de eventos usando código.

Se você estiver usando Visual Basic, você também pode usar a palavra-chave Handles para adicionar manipuladores como parte das declarações do manipulador. Para obter mais informações, consulte Visual Basic and WPF Event Handling.

O conceito de "tratado"

Todos os eventos roteados compartilham uma evento de dados de classe base comum, RoutedEventArgs. RoutedEventArgs Define o Handled propriedade, que tem um valor booliano. O objetivo da propriedade Handled é permitir que qualquer manipulador de eventos ao longo da rota marque o evento roteado como tratado, definindo o valor de Handled como true. Depois de ser processado pelo manipulador em um elemento ao longo da rota, os dados compartilhados do evento são novamente relatados à cada ouvinte na rota.

O valor de Handled afeta como um evento roteado é relatado ou processado a medida que ele viaja mais ao longo da rota. Se Handled é true nos dados de um evento roteado, então os manipuladores que escutam por esse evento roteado em outros elementos geralmente não serão chamados para essa instância específica do evento. Isso é verdade para manipuladores anexados em XAML e para manipuladores adicionados por sintaxes de anexação de manipuladores específicas de linguagens, como += ou Handles. Para cenários mais comuns de manipuladores, marcar um evento como tratado através da definição de Handled como true irá "parar" o roteamento em rotas de tunelamento ou bolha; e também para o roteamento de qualquer evento que seja tratado em algum ponto da rota por um manipulador de classe.

No entanto, há um mecanismo "handledEventsToo" no qual ouvintes podem ainda executar manipuladores em resposta a eventos roteados onde Handled seja true nos dados do evento. Em outras palavras, a rota do evento não é realmente parada ao marcá-lo como tratado nos dados do evento. Você só pode usar o mecanismo handledEventsToo em código, ou em um EventSetter:

Além do comportamento que o estado Handled produz nos eventos roteados, o conceito de Handled tem implicações em como você deve projetar o aplicativo e escrever o código manipulador de eventos. Você pode conceitualizar Handled como sendo um protocolo simples que é exposto por eventos roteados. Exatamente como você usa esse protocolo depende de você, mas o projeto conceitual sobre como o valor de Handled deve ser usado é o seguinte:

  • Se um evento roteado estiver marcado como tratado, então ele não precisa ser tratado novamente por outros elementos ao longo da rota.

  • Se um evento roteado não estiver marcado como tratado, então outros ouvintes anteriores na rota ou escolheram não registrar um manipulador, ou os manipuladores que foram registrados decidiram não manipular os dados do evento dados e definir Handled como true. (Ou, é possível que o ouvinte atual seja o primeiro ponto na rota.) Manipuladores no ouvinte atual tem três possíveis cursos de ação:

    • Não executar nenhuma ação; o evento permanece não tratado e é roteado para o próximo ouvinte.

    • Executar código em resposta ao evento, mas determinar que a ação não foi substancial suficiente para garantir que o evento seja marcado como tratado. O evento é roteado para o próximo ouvinte.

    • Executar código em resposta ao evento. Marcar o evento como tratado nos dados do evento passados para o manipulador, pois a ação foi considerada substancial o suficiente para garantir a marcação como tratado. O evento ainda é roteado para o próximo ouvinte, mas com Handled=true nos dados do evento, para que apenas ouvintes handledEventsToo tenham a oportunidade de invocar mais manipuladores.

Esse design conceitual é reforçado pelo roteamento comportamento mencionado anteriormente: é mais difícil (embora ainda é possível no código ou estilos) anexar manipuladores de eventos roteados são invocados, mesmo se um manipulador anterior na rota já tiver definido Handled para true.

Para obter mais informações sobre Handled, tratamento de eventos roteados por classe e recomendações sobre quando é adequado marcar um evento roteado como Handled, consulte Marcando Eventos Roteados como Manipulados e Manipulação de Classes.

Em aplicativos, é muito comum manipular um evento roteado bolha apenas no objeto que o gerou, e não se preocupar com as características de roteamento do evento. No entanto, ainda assim é uma boa prática marcar o evento roteado como tratado nos dados do evento, para evitar efeitos colaterais não previstos no caso um elemento mais para cima na árvore de elementos também ter um manipulador anexado para esse evento roteado.

Manipuladores por classe

Se você estiver definindo uma classe que deriva de alguma forma de DependencyObject, você também pode definir e anexar um manipulador por classe para um evento roteado que seja um membro declarado ou herdado da sua classe. Manipuladores por classe são chamados antes de quaisquer manipuladores ouvintes de instância que estejam anexados a uma instância da classe, sempre que um evento roteado atinge uma instância de um elemento em sua rota.

Alguns controles WPF têm tratamento inerente à classe para certos eventos roteados. Isso pode dar a impressão de que o evento roteado nunca é gerado, mas na verdade ele está sendo tratado pela classe, e o evento roteado potencialmente ainda pode ser tratado por seus manipuladores de instância se você usar determinadas técnicas. Além disso, muitas classes base e controles expõem métodos virtuais que podem ser usados para sobrecrever o comportamento de tratamento por classe. Para obter mais informações tanto sobre como contornar tratamento por classe indesejado quanto sobre como definir seu próprio tratamento por classe em uma classe personalizada, consulte Marcando Eventos Roteados como Manipulados e Manipulação de Classes.

Eventos anexados no WPF

A linguagem XAML também define um tipo especial de evento chamado de evento anexado. Um evento anexado permite que você adicione um manipulador para um determinado evento em um elemento arbitrário. O elemento tratando o evento não precisa definir ou herdar o evento anexado, e nem o objeto que potencialmente lança o evento nem a instância destino de tratamento devem definir ou "ser donos" desse evento como um membro da classe.

O sistema de entrada do WPF usa eventos anexados amplamente. No entanto, quase todos esses eventos anexados são encaminhados através de elementos base. Os eventos de entrada aparecem como eventos roteados não conectados equivalentes que são membros da classe base de um elemento. Por exemplo, o evento anexado Mouse.MouseDown subjacente pode mais facilmente ser tratado em qualquer UIElement usando-se MouseDown no UIElement ao invés de lidar com a sintaxe de evento anexado em XAML ou em código.

Para obter mais informações sobre eventos anexados no WPF, consulte Visão geral sobre eventos anexados.

Nomes de eventos qualificados em XAML

Outro uso de sintaxe que se assemelha a sintaxe de evento anexado NomeDoTipo.NomeDoEvento mas não é, estritamente falando, um uso de evento anexado se dá quando você anexa manipuladores para eventos roteados que são criados por elementos filho. Você anexa os manipuladores a um pai comum, para tirar proveito do roteamento de eventos, mesmo que o pai comum talvez não tenha o evento roteado relevante como membro. Considere esse exemplo novamente:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

Aqui, o ouvinte do elemento pai onde o manipulador é adicionado é um StackPanel. No entanto, ele está adicionando um manipulador para um evento roteado que foi declarado e será gerado pela classe Button (ButtonBase na verdade, mas disponível para Button por meio de herança). O Button é "dono" do evento, mas o sistema de eventos roteados permite que manipuladores para qualquer evento roteado sejam anexados a quaisquer ouvintes de instância de UIElement ou ContentElement que poderiam, de outro modo, anexar ouvintes para um evento do common language runtime (CLR). O espaço de nomes xmlns padrão para esses nomes qualificados de atributos de eventos é normalmente o espaço de nomes xmlns padrão do WPF, mas você também pode especificar espaços de nomes prefixados para eventos roteados personalizados. Para obter mais informações sobre xmlns, consulte Espaços de nomes XAML e mapeamentos de espaços de nomes.

Eventos de entrada no WPF

Um aplicativo freqüente de eventos roteados dentro de WPF plataforma é para eventos de entrada. Em WPF, encapsulamento roteado eventos nomes são prefixados com a palavra "Visualização" por convenção. Eventos de entrada geralmente vêm em pares, com um sendo um evento bolha e o outro sendo um evento por tunelamento. Por exemplo, o evento KeyDown e o evento PreviewKeyDown têm a mesma assinatura, com o primeiro sendo o evento de entrada bolha e o segundo sendo o evento de entrada por tunelamento. Ocasionalmente, eventos de entrada só tem uma versão bolha, ou talvez somente uma versão roteada direta. Na documentação, os tópicos sobre evento roteados fazem referências cruzadas a eventos roteados similares com estratégias alternativas de roteamento se tais eventos roteados existirem, e seções nas páginas sobre referências gerenciadas esclarecem a estratégia de roteamento de cada evento roteado.

Os eventos de entrada do WPF que vêm em pares são implementados de modo que uma única ação de entrada do usuário, como um pressionamento de botão do mouse, irá lançar os dois eventos roteados do par em sequência. Primeiro, o evento por tunelamento é gerado e viaja por sua rota. Em seguida, o evento bolha é gerado e viaja por sua rota. Os dois eventos literalmente compartilham a mesma instância dos dados do evento, pois a chamada de método RaiseEvent na implementação da classe que gera o evento bolha espera pelos dados de evento do evento por tunelamento e reutiliza-os no novo evento lançado. Ouvintes com manipuladores para o evento por tunelamento terão primeiro a oportunidade de marcar o evento roteado como tratado (manipuladores por classe em primeiro lugar, em seguida, manipuladores de instâncias). Se um elemento na rota de tunelamento marcou o evento roteado como tratado, os dados do evento já tratado são enviados para o evento bolha, e os manipuladores típicos anexados para o evento de entrada bolha equivalente não serão chamados. A impressão externa será como se o evento bolha tratado nem foi lançado. Esse comportamento de tratamento é útil para composição de um controle, onde você pode querer que todos os eventos de entrada baseados em teste de colisão ou baseados em foco sejam relatados para seu controle final, ao invés das partes da composição. O elemento controle final é o mais próximo da raiz na composição e, portanto, tem a oportunidade de tratar por classe o evento de tunelamento em primeiro lugar; e, talvez, "substituir" o evento roteado por um evento mais específico do controle, como parte do código que dá suporte a classe do controle.

De modo a ilustrar como o processamento de eventos de entrada funciona, considere o seguinte exemplo de evento de entrada. Na árvore mostrada a seguir, leaf element #2 é a origem de um evento PreviewMouseDown e, em seguida, de um evento MouseDown.

Eventos de entrada bolha e por tunelamento

Diagrama de roteamento de eventos

A ordem de processamento de eventos é a seguinte:

  1. PreviewMouseDown (tunelamento) no elemento raiz.

  2. PreviewMouseDown (tunelamento) no elemento intermediário nº 1.

  3. PreviewMouseDown (tunelamento) no elemento origem nº 2.

  4. MouseDown (bolha) no elemento origem nº 2.

  5. MouseDown (bolha) no elemento intermediário nº 1.

  6. MouseDown (bolha) no elemento raiz.

Um delegado manipulador de evento roteado fornece referências para dois objetos: o objeto que disparou o evento e o objeto no qual o manipulador foi chamado. O objeto onde o manipulador foi invocado é o objeto relatado pelo parâmetro sender. O objeto onde o evento foi gerado pela primeira vez é reportado pela propriedade Source nos dados do evento. Um evento roteado pode ainda ser gerado e tratado pelo mesmo objeto. Nesse caso o sender e a Source serão idênticos (esse é o caso das etapas 3 e 4 no exemplo de processamento de eventos).

Devido ao tunelamento e ao comportamento de bolha, os elementos pai recebem eventos de entrada onde a Source é um de seus elementos filho. Quando for importante saber qual é o elemento de origem, você pode identificar o elemento de origem acessando a propriedade Source.

Geralmente, uma vez que o evento de entrada seja marcado como Handled, outros manipuladores não serão chamados. Normalmente, você deve marcar eventos de entrada como tratados, assim que um manipulador invocado atende sua lógica de tratamento específica do aplicativo com relação ao significado do evento de entrada.

A exceção a essa instrução geral sobre o estado Handled é que manipuladores de eventos de entrada que são registrados para ignorar deliberadamente o estado Handled dos dados do evento ainda poderiam ser chamados ao longo de qualquer uma das rotas. Para obter mais informações, consulte Visualização de Eventos ou Marcando Eventos Roteados como Manipulados e Manipulação de Classes.

O modelo de dados de evento compartilhado entre eventos tunelamento/bolha e o lançamento sequencial primeiro de eventos por tunelamento e, em seguida, de eventos bolha, não é um conceito geralmente verdadeiro para todos os eventos roteados. Esse comportamento é especificamente implementado por como dispositivos de entrada WPF escolhem lançar e conectar-se aos pares de evento de entrada. Implementar seus próprios eventos de entrada é um cenário avançado, mas você também pode escolher seguir esse modelo para seus próprios eventos de entrada.

Determinadas classes escolhem manipular por classe certos eventos de entrada, geralmente com a intenção de redefinir o que significa um determinado evento de entrada causado pelo usuário dentro desse controle específico e gerar um novo evento. Para obter mais informações, consulte Marcando Eventos Roteados como Manipulados e Manipulação de Classes.

Para obter mais informações sobre entrada e como entrada e eventos interagem em cenários típicos de aplicativos, consulte Input Overview.

EventSetters e EventTriggers

Em estilos, você pode incluir alguma sintaxe XAML pré-delcarada de tratamento de eventos na marcação usando um EventSetter. Quando o estilo é aplicado, o manipulador referenciado é adicionado à instância estilizada. Você pode declarar um EventSetter somente para um evento roteado. The following is an example. Observe que o método b1SetColor referenciado aqui está em um arquivo de código por trás da marcação.

<StackPanel
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.EventOvw2"
  Name="dpanel2"
  Initialized="PrimeHandledToo"
>
  <StackPanel.Resources>
    <Style TargetType="{x:Type Button}">
      <EventSetter Event="Click" Handler="b1SetColor"/>
    </Style>
  </StackPanel.Resources>
  <Button>Click me</Button>
  <Button Name="ThisButton" Click="HandleThis">
    Raise event, handle it, use handled=true handler to get it anyway.
  </Button>
</StackPanel>

A vantagem ganha aqui é que o estilo provavelmente contêm uma grande quantidade de outras informações que podem aplicar-se a qualquer botão em seu aplicativo, e ter o EventSetter fazendo parte desse estilo promove a reutilização de código mesmo no nível de marcação. Além disso, um EventSetter abstrai os nomes dos método para os manipuladores criando um nível a mais de distância do aplicativo e da página em linguagem de marcação.

Outra sintaxe especializada que combina os recursos do WPF de eventos roteados e de animação é um EventTrigger. sistema autônomo ocorre com EventSetter, eventos roteados só podem ser usados para um EventTrigger. Normalmente, um EventTrigger é declarada sistema autônomo parte de um estilo, mas um EventTrigger também pode ser declarada em elementos de nível de página sistema autônomo parte do Triggers coleção, ou em um ControlTemplate. Um EventTrigger permite que você especifique um Storyboard que é executado sempre que um evento roteado atinge um elemento na respectiva rota declara um EventTrigger para esse evento. A vantagem de um EventTrigger sobre simplesmente manipulando o evento e fazendo com que ele iniciar um storyboard existente é que um EventTrigger Fornece um melhor controle sobre o storyboard e seu comportamento em time de execução. Para obter mais informações, consulte Como: Usar acionadores de eventos para controlar um Storyboard após seu início.

Mais informações sobre eventos roteados

Este tópico aborda principalmente eventos roteados da perspectiva de descrever os conceitos básicos e oferecer orientação sobre como e quando responder a eventos roteados que já estão presente nos vários elementos base e controles. No entanto, você pode criar seu próprio evento roteado em sua classe personalizada juntamente com todo o suporte necessário, tal como classes especializadas de dados de eventos e delegados. Qualquer classe pode ser proprietária de um evento roteado, mas eventos roteados devem ser gerados e tratados por uma classe derivada de UIElement ou de ContentElementpara ser útil. Para obter mais informações sobre eventos personalizados, consulte Como: Criar um evento roteado personalizado.

Consulte também

Conceitos

Marcando Eventos Roteados como Manipulados e Manipulação de Classes

Input Overview

Visão geral de Comando

Propriedades de Dependência Personalizada

Árvores em WPF

Padrões WeakEvent

Referência

EventManager

RoutedEvent

RoutedEventArgs