Partilhar via


Visão geral de eventos roteados (WPF .NET)

Os desenvolvedores de aplicativos e autores de componentes do Windows Presentation Foundation (WPF) podem usar eventos roteados para propagar eventos por meio de uma árvore de elementos e invocar manipuladores de eventos em vários ouvintes na árvore. Esses recursos não são encontrados em eventos CLR (Common Language Runtime). Vários eventos WPF são eventos roteados, como ButtonBase.Click. Este artigo discute conceitos básicos de eventos roteados e oferece orientação sobre quando e como responder a eventos roteados.

Pré-requisitos

Este artigo pressupõe um conhecimento básico do Common Language Runtime (CLR), programação orientada a objetos e como layout de elemento WPF pode ser conceituado como uma árvore. Para seguir os exemplos neste artigo, isso ajuda se você estiver familiarizado com Extensible Application Markup Language (XAML) e souber como escrever aplicativos WPF.

O que é um evento roteado?

Você pode considerar eventos roteados de uma perspetiva funcional ou de implementação:

  • De uma perspetiva de funcional , um evento roteado é um tipo de evento que pode invocar manipuladores em vários ouvintes em uma árvore de elementos, não apenas na fonte do evento. Um ouvinte de eventos é o elemento onde um manipulador de eventos é anexado e invocado. Uma fonte de evento é o elemento ou objeto que originalmente gerou um evento.

  • De uma perspetiva implementação , um evento roteado é um evento registrado no sistema de eventos WPF, apoiado por uma instância da classe e processado pelo sistema de eventos WPF. Normalmente, um evento de encaminhamento é implementado com um "wrapper" de evento CLR para permitir a atribuição de manipuladores em XAML e no código subjacente, como faria com um evento CLR.

Os aplicativos WPF normalmente contêm muitos elementos, que foram declarados em XAML ou instanciados em código. Os elementos de um aplicativo existem dentro de sua árvore de elementos. Dependendo de como um evento roteado é definido, quando o evento é gerado em um elemento de origem, ele:

  • Propaga-se através da árvore de elementos desde o elemento de origem até ao elemento raiz, que normalmente é uma página ou janela.
  • Percorre a árvore de elementos desde o elemento raiz até o elemento de origem.
  • Não viaja pela árvore de elementos e ocorre apenas no elemento de origem.

Considere a seguinte árvore parcial de elementos:

<Border Height="30" Width="200" BorderBrush="Gray" BorderThickness="1">
    <StackPanel Background="LightBlue" Orientation="Horizontal" Button.Click="YesNoCancelButton_Click">
        <Button Name="YesButton">Yes</Button>
        <Button Name="NoButton">No</Button>
        <Button Name="CancelButton">Cancel</Button>
    </StackPanel>
</Border>

A árvore de elementos renderiza conforme mostrado:

Uma árvore de elementos XAML com três botões: Sim, Não e Cancelar.

Cada um dos três botões é uma potencial fonte de eventos Click. Quando um dos botões é clicado, ele gera o evento Click que se propaga do botão para o elemento raiz. Os elementos Button e Border não têm manipuladores de eventos anexados, mas o StackPanel tem. Possivelmente, outros elementos mais acima na árvore que não são mostrados também têm manipuladores de eventos Click anexados. Quando o evento Click atinge o elemento StackPanel, o sistema de eventos WPF invoca o manipulador de YesNoCancelButton_Click que está anexado a ele. A rota de evento para o evento Click no exemplo é: Button ->StackPanel ->Border -> elementos pai sucessivos.

Observação

O elemento que originalmente gerou um evento roteado é identificado como o RoutedEventArgs.Source nos parâmetros do manipulador de eventos. O ouvinte de eventos é o elemento onde o manipulador de eventos é anexado e invocado, e é identificado como o remetente nos parâmetros do manipulador de eventos.

Cenários de nível superior para eventos roteados

Aqui estão alguns dos cenários que motivaram o conceito de evento roteado e o distinguem de um evento CLR típico:

  • Composição de controle e encapsulamento: Vários controles no WPF têm um modelo de conteúdo rico. Por exemplo, você pode colocar uma imagem dentro de um Button, o que efetivamente estende a árvore visual do botão. Mas, a imagem adicionada não deve quebrar o comportamento de teste de acerto do botão, que precisa responder quando um usuário clica nos pixels da imagem.

  • Pontos de anexação de manipulador singular: Pode-se registrar um manipulador para o evento Click de cada botão, mas com eventos encaminhados é possível anexar um único manipulador, conforme mostrado no exemplo XAML anterior. Isso permite que você altere a árvore de elementos sob o manipulador singular, como adicionar ou remover mais botões, sem ter que registrar o evento Click de cada botão. Quando o evento Click é gerado, a lógica do manipulador pode determinar de onde o evento veio. O manipulador a seguir, especificado na árvore de elementos XAML mostrada anteriormente, contém essa lógica:

    private void YesNoCancelButton_Click(object sender, RoutedEventArgs e)
    {
        FrameworkElement sourceFrameworkElement = e.Source as FrameworkElement;
        switch (sourceFrameworkElement.Name)
        {
            case "YesButton":
                // YesButton logic.
                break;
            case "NoButton":
                // NoButton logic.
                break;
            case "CancelButton":
                // CancelButton logic.
                break;
        }
        e.Handled = true;
    }
    
    Private Sub YesNoCancelButton_Click(sender As Object, e As RoutedEventArgs)
        Dim frameworkElementSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
    
        Select Case frameworkElementSource.Name
            Case "YesButton"
                ' YesButton logic.
            Case "NoButton"
                ' NoButton logic.
            Case "CancelButton"
                ' CancelButton logic.
        End Select
    
        e.Handled = True
    End Sub
    
  • Manipulação de classe: Os eventos roteados suportam um manipulador de eventos de classe que você define em uma classe. Os manipuladores de classe manipulam um evento antes de qualquer manipulador de instância para o mesmo evento em qualquer instância da classe.

  • Fazendo referência a um evento sem reflexão: cada evento roteado cria um identificador de campo RoutedEvent para fornecer uma técnica robusta de identificação de eventos que não requer reflexão estática ou em tempo de execução para identificar o evento.

Como os eventos roteados são implementados

Um evento roteado é um evento registrado no sistema de eventos WPF, apoiado por uma instância da classe RoutedEvent e processado pelo sistema de eventos WPF. A instância , obtida a partir do registoem , normalmente é armazenada como membro da classe que a registou. Essa classe é conhecida como a classe "proprietário" do evento. Normalmente, um evento encaminhado implementa um evento CLR com o mesmo nome, chamado "wrapper". O wrapper de eventos CLR contém os acessores add e remove para habilitar a anexação de manipuladores em XAML e no código subjacente através da sintaxe de eventos específica da linguagem. Os acessadores add e remove sobrepõem à sua implementação CLR e chamam os métodos e eventos roteados AddHandler e RemoveHandler. O mecanismo de suporte e conexão de eventos encaminhados é conceitualmente semelhante ao modo como uma propriedade de dependência é uma propriedade CLR suportada pela classe DependencyProperty e registrada no sistema de propriedades WPF.

O exemplo a seguir registra o evento Tap roteado, armazena a instância de RoutedEvent retornada e implementa um wrapper de evento CLR.

// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
    name: "Tap",
    routingStrategy: RoutingStrategy.Bubble,
    handlerType: typeof(RoutedEventHandler),
    ownerType: typeof(CustomButton));

// Provide CLR accessors for adding and removing an event handler.
public event RoutedEventHandler Tap
{
    add { AddHandler(TapEvent, value); }
    remove { RemoveHandler(TapEvent, value); }
}
' Register a custom routed event using the Bubble routing strategy.
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
    name:="Tap",
    routingStrategy:=RoutingStrategy.Bubble,
    handlerType:=GetType(RoutedEventHandler),
    ownerType:=GetType(CustomButton))

' Provide CLR accessors for adding and removing an event handler.
Public Custom Event Tap As RoutedEventHandler
    AddHandler(value As RoutedEventHandler)
        [AddHandler](TapEvent, value)
    End AddHandler

    RemoveHandler(value As RoutedEventHandler)
        [RemoveHandler](TapEvent, value)
    End RemoveHandler

    RaiseEvent(sender As Object, e As RoutedEventArgs)
        [RaiseEvent](e)
    End RaiseEvent
End Event

Estratégias de roteamento

Os eventos roteados usam uma das três estratégias de roteamento:

  • Bubbling: Inicialmente, os manipuladores de eventos na fonte de eventos são invocados. Em seguida, o evento roteado é encaminhado para elementos pai sucessivos, invocando seus manipuladores de eventos por sua vez, até atingir a raiz da árvore de elementos. A maioria dos eventos roteados usa a estratégia de roteamento por propagação. Os eventos roteados borbulhantes geralmente são usados para relatar alterações de entrada ou estado de controles compostos ou outros elementos da interface do usuário.

  • Tunneling: Inicialmente, são invocados os manipuladores de eventos na raiz da árvore de elementos. Em seguida, o evento roteado é encaminhado para elementos filho sucessivos, invocando seus manipuladores de eventos por sua vez, até chegar à origem do evento. Os eventos que seguem uma rota de túnel também são chamados de eventos Preview. Os eventos de entrada do WPF geralmente são implementados como uma visualização e pares borbulhantes.

  • Direct: Somente manipuladores de eventos na fonte de eventos são invocados. Essa estratégia de não roteamento é análoga aos eventos da estrutura da interface do usuário do Windows Forms, que são eventos CLR padrão. Ao contrário dos eventos CLR, os eventos roteados diretos suportam manipulação de classe e podem ser usados por EventSetters e EventTriggers.

Por que usar eventos roteados?

Como desenvolvedor de aplicativos, você nem sempre precisa saber ou se preocupar que o evento que você está manipulando seja implementado como um evento roteado. Os eventos roteados têm um comportamento especial, mas esse comportamento é praticamente invisível se você estiver manipulando um evento no elemento que o gerou. No entanto, os eventos roteados são relevantes quando você deseja anexar um manipulador de eventos a um elemento pai para manipular eventos gerados por elementos filho, como dentro de um controle composto.

Os ouvintes de eventos roteados não precisam que os eventos roteados que eles manipulam sejam membros da sua classe. Qualquer UIElement ou ContentElement pode ser um ouvinte de eventos para qualquer evento roteado. Como os elementos visuais derivam de UIElement ou ContentElement, você pode usar eventos roteados como uma "interface" conceitual que suporta a troca de informações de eventos entre elementos diferentes em um aplicativo. O conceito de "interface" para eventos roteados é particularmente aplicável a eventos de entrada .

Os eventos roteados suportam a troca de informações de eventos entre elementos ao longo da rota do evento porque cada ouvinte tem acesso à mesma instância de dados de eventos. Se um elemento alterar algo nos dados do evento, essa alteração será visível para os elementos subsequentes na rota do evento.

Além do aspeto de roteamento, você pode optar por implementar um evento roteado em vez de um evento CLR padrão pelos seguintes motivos:

  • Alguns recursos de modelagem e estilo do WPF, como EventSetters e EventTriggers, exigem que o evento referenciado seja um evento roteado.

  • Os eventos roteados suportam manipuladores de eventos de classe que manipulam um evento à frente de qualquer manipulador de instância para o mesmo evento em qualquer instância da classe listener. Esse recurso é útil no design de controle porque seu manipulador de classe pode impor comportamentos de classe controlados por eventos que não podem ser suprimidos acidentalmente por um manipulador de instância.

Anexar e implementar um manipulador de eventos roteado

Em XAML, você anexa um manipulador de eventos a um elemento declarando o nome do evento como um atributo no elemento ouvinte de eventos. O valor do atributo é o nome do método do manipulador. O método handler deve ser implementado na classe parcial code-behind para a página XAML. O ouvinte de eventos é o elemento onde o manipulador de eventos é anexado e invocado.

Para um evento que seja um membro (herdado ou não) da classe listener, você pode anexar um manipulador da seguinte maneira:

<Button Name="Button1" Click="Button_Click">Click me</Button>

Se o evento não for um membro da classe do ouvinte, você deverá usar o nome do evento qualificado na forma de <owner type>.<event name>. Por exemplo, como a classe StackPanel não implementa o evento Click, para anexar um manipulador a um StackPanel para um evento Click que se propaga até esse elemento, será necessário usar a sintaxe de nome de evento qualificado:

<StackPanel Name="StackPanel1" Button.Click="Button_Click">
    <Button>Click me</Button>
</StackPanel>

A assinatura do método manipulador de eventos no code-behind deve corresponder ao tipo de delegado para o evento roteado. O parâmetro sender do delegado RoutedEventHandler para o evento Click especifica o elemento ao qual o manipulador de eventos está anexado. O parâmetro args do delegado RoutedEventHandler contém os dados do evento. Uma implementação code-behind compatível para o manipulador de eventos Button_Click pode ser:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // Click event logic.
}
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    ' Click event logic.
End Sub

Embora RoutedEventHandler seja o delegado básico do manipulador de eventos roteados, alguns controles ou cenários de implementação exigem delegados diferentes que oferecem suporte a dados de eventos mais especializados. Por exemplo, para o evento DragEnter encaminhado, o seu manipulador deve implementar o delegado DragEventHandler. Ao fazer isso, o código do manipulador pode acessar a propriedade DragEventArgs.Data nos dados de evento, que contém o conteúdo da área de transferência da operação de arrastar.

A sintaxe XAML para adicionar manipuladores de eventos roteados é a mesma que para manipuladores de eventos CLR padrão. Para obter mais informações sobre como adicionar manipuladores de eventos em XAML, consulte XAML no WPF. Para obter um exemplo completo de como anexar um manipulador de eventos a um elemento usando XAML, consulte Como manipular um evento encaminhado.

Para anexar um manipulador de eventos para um evento roteado a um elemento usando código, você geralmente tem duas opções:

  • Chame diretamente o método AddHandler. Os manipuladores de eventos roteados podem sempre ser ligados desta maneira. Este exemplo anexa um manipulador de eventos Click a um button usando o método AddHandler:

    Button1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    Button1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    

    Para anexar um manipulador do evento Click do botão a um elemento diferente no caminho do evento, como um StackPanel chamado StackPanel1:

    StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    
  • Se o evento roteado implementar um invólucro de evento CLR, use a sintaxe de evento específica da linguagem para adicionar manipuladores de eventos da mesma forma que faria para um evento CLR padrão. A maioria dos eventos roteados do WPF existentes implementa o wrapper CLR, permitindo assim a sintaxe de eventos específica do idioma. Este exemplo anexa um manipulador de eventos Click a um button usando sintaxe específica do idioma:

    Button1.Click += Button_Click;
    
    AddHandler Button1.Click, AddressOf Button_Click
    

Para obter um exemplo de como anexar um manipulador de eventos no código, consulte Como adicionar um manipulador de eventos usando o código. Se você estiver codificando no Visual Basic, também poderá usar a palavra-chave Handles para adicionar manipuladores como parte das declarações do manipulador. Para obter mais informações, consulte Visual Basic e WPF manipulação de eventos.

O conceito de manipulado

Todos os eventos roteados compartilham uma classe base comum para dados de eventos, que é a classe RoutedEventArgs. A classe RoutedEventArgs define a propriedade boolean Handled. A finalidade da propriedade Handled é permitir que qualquer manipulador de eventos ao longo da rota de eventos marque o evento roteado como manipulado. Para marcar um evento como manipulado, defina o valor de Handled como true no código do manipulador de eventos.

O valor de Handled afeta como um evento roteado é processado à medida que viaja ao longo da rota do evento. Se Handled estiver true nos dados de evento compartilhados de um evento roteado, os manipuladores anexados a outros elementos ao longo da rota de evento normalmente não serão invocados para essa instância de evento específica. Para os cenários de manipulador mais comuns, marcar um evento como manipulado efetivamente impede que manipuladores subsequentes ao longo da rota de eventos, sejam manipuladores de instância ou classe, respondam a essa instância de evento específica. No entanto, em casos raros em que você precisa que seu manipulador de eventos responda a eventos roteados que foram marcados como manipulados, você pode:

O conceito de Handled pode afetar como você projeta seu aplicativo e codifica seus manipuladores de eventos. Você pode conceituar Handled como um protocolo simples para processamento de eventos roteados. A forma como você usa esse protocolo depende de você, mas o uso esperado do parâmetro Handled é:

  • Se um evento roteado for marcado como manipulado, ele não precisará ser manipulado novamente por outros elementos ao longo da rota.

  • Se um evento roteado não estiver marcado como manipulado, os ouvintes anteriores na rota do evento não terão um manipulador para o evento ou nenhum dos manipuladores registrados respondeu ao evento de uma forma que justifique marcar o evento como manipulado. Os manipuladores no ouvinte atual têm três cursos de ação possíveis:

    • Não tome nenhuma medida. O evento permanece sem tratamento e é encaminhado para o próximo ouvinte na árvore.

    • Execute o código em resposta ao evento, mas não numa medida que justifique marcar o evento como tratado. O evento permanece não tratado e é encaminhado para o próximo ouvinte na árvore.

    • Execute o código em resposta ao evento, até ao ponto suficiente para justificar considerar o evento como tratado. Marque o evento como tratado nos dados do evento. O evento ainda é encaminhado para o próximo listener na árvore, mas a maioria dos listeners não invocará manipuladores adicionais. A exceção são os ouvintes com manipuladores que foram especificamente registrados com handledEventsToo definidos como true.

Para obter mais informações sobre como manipular eventos roteados, consulte Marcando eventos roteados como manipulados ede manipulação de classe .

Embora os desenvolvedores que manipulam apenas um evento roteado borbulhante no objeto que o gerou possam não estar preocupados com outros ouvintes, é uma boa prática marcar o evento como manipulado de qualquer maneira. Isso evita efeitos colaterais imprevistos se um elemento mais adiante na rota do evento tiver um manipulador para o mesmo evento roteado.

Gestores de classe

Os manipuladores de eventos encaminhados podem ser manipuladores de instância ou manipuladores de classe . Os manipuladores de classe para uma determinada classe são invocados antes de qualquer manipulador de instância que responda ao mesmo evento em qualquer instância dessa classe. Devido a esse comportamento, quando os eventos enviados são marcados como manipulados, eles muitas vezes são assinalados dessa forma em manipuladores de classe. Há dois tipos de manipuladores de classe:

Alguns controles WPF têm manipulação de classe inerente para determinados eventos roteados. A manipulação de classe pode dar a aparência externa de que o evento roteado nunca foi gerado, mas na realidade está sendo marcado como manipulado por um manipulador de classe. Se você precisar que seu manipulador de eventos responda ao evento manipulado, poderá registrar seu manipulador com handledEventsToo definido como true. Para obter mais informações, quer sobre como implementar os seus próprios manipuladores de classe, quer sobre como contornar a manipulação de classe indesejada, consulte Marcando eventos roteados como manipulados e manipulação de classe.

Eventos anexados no WPF

A linguagem XAML também define um tipo especial de evento chamado evento anexado. Os eventos anexados podem ser usados para definir um novo evento roteado numa classe que não é de elemento e desencadear esse evento em qualquer elemento na sua árvore. Para fazer isso, deve-se registar o evento anexado como um evento encaminhado e fornecer código de suporte específico que ofereça suporte à funcionalidade de evento anexado. Como os eventos anexados são registrados como eventos roteados, quando gerados em um elemento eles se propagam pela árvore de elementos.

Na sintaxe XAML, um evento anexado é especificado pelo nome do evento e pelo tipo de proprietário, no formato <owner type>.<event name>. Como o nome do evento é qualificado com o nome do seu tipo de proprietário, a sintaxe permite que o evento seja associado a qualquer elemento que possa ser instanciado. Essa sintaxe também é aplicável a manipuladores de eventos roteados regulares que se anexam a um elemento arbitrário ao longo da rota de evento. Você também pode anexar manipuladores para eventos anexados no code-behind chamando o método AddHandler no objeto ao qual o manipulador deve anexar.

O sistema de entrada WPF usa eventos anexados extensivamente. No entanto, quase todos esses eventos anexados são apresentados como eventos roteados não anexados equivalentes através de elementos base. Você raramente usará ou manipulará eventos anexados diretamente. Por exemplo, é mais fácil manipular o evento Mouse.MouseDown anexado subjacente num UIElement através do evento equivalente UIElement.MouseDown roteado do que usando a sintaxe de evento anexado em XAML ou no code-behind.

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

Nomes de eventos qualificados em XAML

A sintaxe <owner type>.<event name> qualifica um nome de evento com o nome de seu tipo de proprietário. Essa sintaxe permite que um evento seja anexado a qualquer elemento, não apenas a elementos que implementam o evento como um membro de sua classe. A sintaxe é aplicável ao anexar manipuladores em XAML para eventos anexados ou eventos encaminhados em elementos arbitrários ao longo da rota de eventos. Considere o cenário em que você deseja anexar um manipulador a um elemento pai para manipular eventos roteados gerados em elementos filho. Se o elemento pai não tiver o evento roteado como membro, você precisará usar a sintaxe do nome do evento qualificado. Por exemplo:

<StackPanel Name="StackPanel1" Button.Click="Button_Click">
    <Button>Click me</Button>
</StackPanel>

No exemplo, o ouvinte do elemento pai ao qual o manipulador de eventos é adicionado é um StackPanel. No entanto, o evento Click roteado é implementado e gerado na classe ButtonBase e disponível para a classe Button por meio de herança. Embora a classe Button "possua" o evento Click, o sistema de eventos roteado permite que manipuladores para qualquer evento roteado sejam anexados a qualquer ouvinte de instância UIElement ou ContentElement que poderia ter manipuladores para um evento CLR. O namespace xmlns padrão para esses nomes de atributo de evento qualificado é normalmente o namespace WPF xmlns padrão, mas você também pode especificar namespaces prefixados para eventos roteados personalizados. Para obter mais informações sobre xmlns, consulte namespaces XAML e mapeamento de namespace para WPF XAML.

Eventos de entrada do WPF

Uma aplicação frequente de eventos roteados dentro da plataforma WPF é para eventos de entrada. Por convenção, os eventos encaminhados do WPF que seguem uma rota de tunelamento têm um nome com o prefixo "Preview". O prefixo Preview significa que o evento de visualização é concluído antes do início do evento borbulhante emparelhado. Os eventos de entrada geralmente vêm em pares, com um sendo um evento de visualização e o outro um evento roteado borbulhante. Por exemplo, PreviewKeyDown e KeyDown. Os pares de eventos compartilham a mesma instância de dados de evento, que para PreviewKeyDown e KeyDown é do tipo KeyEventArgs. Ocasionalmente, os eventos de entrada têm apenas uma versão borbulhante ou apenas uma versão roteada diretamente. Na documentação da API, os tópicos de eventos roteados fazem referência cruzada a pares de eventos roteados e esclarecem a estratégia de roteamento para cada evento roteado.

Os eventos de entrada do WPF que vêm em pares são implementados de forma que uma única ação de um utilizador num dispositivo de entrada, como pressionar um botão do rato, desencadeie, em sequência, os eventos roteados de pré-visualização e bubbling. Primeiro, o evento de pré-visualização é gerado e conclui o seu percurso. Após a conclusão do evento de visualização, o evento borbulhante é levantado e completa sua rota. A chamada do método RaiseEvent na classe de implementação que gera o evento de propagação reutiliza os dados do evento de pré-visualização para o evento de propagação.

Um evento de entrada de visualização marcado como manipulado não invocará nenhum manipulador de eventos normalmente registrado para o restante da rota de visualização, e o evento borbulhante emparelhado não será gerado. Esse comportamento de manipulação é útil para designers de controles compostos que desejam que eventos de entrada baseados em teste de acerto ou eventos de entrada baseados em foco sejam relatados no nível superior de seu controle. Os elementos de nível superior do controle têm a oportunidade de manipular eventos de visualização de classe de subcomponentes de controle para "substituí-los" por um evento específico de controle de nível superior.

Para ilustrar como funciona o processamento de eventos de entrada, considere o exemplo de evento de entrada a seguir. Na ilustração de árvore a seguir, leaf element #2 é a fonte dos eventos PreviewMouseDown e MouseDown emparelhados:

Um diagrama que mostra como o roteamento de eventos flui de um elemento raiz para outros elementos.

A ordem de processamento de eventos após uma ação de mouse para baixo no elemento folha #2 é:

  1. Evento de tunelamento PreviewMouseDown no elemento raiz.
  2. PreviewMouseDown evento de tunelamento no elemento intermediário #1.
  3. PreviewMouseDown evento de tunelização no elemento folha #2, que é o elemento fonte.
  4. MouseDown evento borbulhante no elemento folha #2, que é o elemento fonte.
  5. MouseDown evento borbulhante no elemento intermediário #1.
  6. MouseDown evento de propagação no elemento raiz.

O delegado do manipulador de eventos roteado fornece referências ao objeto que gerou o evento e ao objeto onde o manipulador foi chamado. O objeto que originalmente gerou o evento é indicado pela propriedade Source nos dados do evento. O objeto onde o manipulador foi invocado é relatado pelo sender parâmetro. Para qualquer instância de evento roteado, o objeto que gerou o evento não muda à medida que o evento viaja pela árvore de elementos, mas o sender sim. Nas etapas 3 e 4 do diagrama anterior, as Source e sender são o mesmo objeto.

Se o manipulador de eventos de entrada concluir a lógica específica do aplicativo necessária para abordar o evento, você deverá marcar o evento de entrada como manipulado. Normalmente, quando um evento de entrada é marcado Handled, os manipuladores mais adiantados na rota do evento não são invocados. No entanto, os manipuladores de eventos de entrada registrados com o parâmetro handledEventsToo definido como true serão invocados mesmo quando o evento for marcado como manipulado. Para obter mais informações, consulte Pré-visualização de eventos e Marcando eventos roteados como manipulados emanipulação de classe.

O conceito de pares de eventos de pré-visualização e de propagação, com dados de eventos partilhados e ativação sequencial do evento de pré-visualização seguido pelo evento de propagação, aplica-se apenas a alguns eventos de entrada do WPF e não a todos os eventos roteados. Se você implementar seu próprio evento de entrada para abordar um cenário avançado, considere seguir a abordagem de par de eventos de entrada do WPF.

Se você estiver implementando seu próprio controle composto que responde a eventos de entrada, considere usar eventos de visualização para suprimir e substituir eventos de entrada gerados em subcomponentes por um evento de nível superior que representa o controle completo. Para obter mais informações, consulte Marcando eventos encaminhados como manipulados e manipulação de classes.

Para obter mais informações sobre o sistema de entrada WPF e como entradas e eventos interagem em cenários típicos de aplicativos, consulte Visão geral de entrada .

Definidores de Eventos e Disparadores de Eventos

Em estilos de marcação, você pode incluir sintaxe de manipulação de eventos XAML pré-declarada usando um EventSetter. Quando o XAML é processado, o manipulador referenciado é adicionado à instância estilizada. Você só pode declarar um EventSetter para um evento roteado. No exemplo a seguir, o método manipulador de eventos ApplyButtonStyle referenciado é implementado no code-behind.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type Button}">
            <EventSetter Event="Click" Handler="ApplyButtonStyle"/>
        </Style>
    </StackPanel.Resources>
    <Button>Click me</Button>
    <Button Click="Button_Click">Click me</Button>
</StackPanel>

É provável que o nó Style já contenha outras informações de estilo que pertencem a controles do tipo especificado, e ter o EventSetter fazer parte desses estilos promove a reutilização de código mesmo no nível de marcação. Além disso, um EventSetter abstrai nomes de método para manipuladores, separando-os do aplicativo geral e da marcação de página.

Outra sintaxe especializada que combina o evento roteado e os recursos de animação do WPF é um EventTrigger. Tal como acontece com o EventSetter, só pode declarar um EventTrigger para um evento roteado. Normalmente, um EventTrigger é declarado como parte de um estilo, mas um EventTrigger pode ser declarado em elementos de nível de página como parte da coleção Triggers ou em um ControlTemplate. Um EventTrigger permite especificar um Storyboard que é executado sempre que um evento roteado atinge um elemento em sua rota que declara um EventTrigger para esse evento. A vantagem de um EventTrigger sobre apenas lidar com o evento e fazer com que ele inicie um storyboard existente é que um EventTrigger fornece um melhor controle sobre o storyboard e seu comportamento em tempo de execução. Para obter mais informações, consulte Usar gatilhos de evento para controlar um storyboard depois de este começar.

Mais sobre eventos encaminhados

Você pode usar os conceitos e orientações neste artigo como um ponto de partida ao criar eventos roteados personalizados em suas próprias classes. Você também pode dar suporte a seus eventos personalizados com classes de dados de eventos especializados e delegados. Um proprietário de evento roteado pode ser qualquer classe, mas os eventos roteados devem ser gerados e manipulados por UIElement ou ContentElement classes derivadas para serem úteis. Para obter mais informações sobre eventos personalizados, consulte Criar um evento roteado personalizado.

Ver também