Compartilhar 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 do WPF são eventos roteados, como ButtonBase.Click. Este artigo discute conceitos básicos de eventos roteados e oferece diretrizes sobre quando e como responder a eventos roteados.

Pré-requisitos

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

O que é um evento roteado?

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

  • De uma perspectiva 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 origem do evento. Um ouvinte de eventos é o elemento em que um manipulador de eventos é anexado e invocado. Uma origem de evento é o elemento ou objeto que originalmente gerou um evento.

  • De uma perspectiva de implementação , um evento roteado é um evento registrado com o sistema de eventos do WPF, apoiado por uma instância da classe e processado pelo sistema de RoutedEvent eventos do WPF. Normalmente, um evento roteado é implementado com um "wrapper" de evento CLR para habilitar a anexação de manipuladores em XAML e em code-behind como você faria com um evento CLR.

Os aplicativos WPF normalmente contêm muitos elementos, que foram declarados em XAML ou instanciados no 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:

  • Bolha através da árvore de elementos do elemento de origem para o elemento raiz, que normalmente é uma página ou janela.
  • Túneis para baixo através da árvore de elementos do elemento raiz para o elemento de origem.
  • Não percorre a árvore de elementos e ocorre apenas no elemento de origem.

Considere a seguinte árvore de elementos parciais:

<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 é renderizada 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 fonte de evento potencial Click . Quando um dos botões é clicado, ele gera o Click evento que borbulha do botão para o elemento raiz. Os Button elementos and Border não têm manipuladores de eventos anexados, mas sim StackPanel . Possivelmente, outros elementos mais altos na árvore que não são mostrados também têm Click manipuladores de eventos anexados. Quando o Click evento atinge o StackPanel elemento, o sistema de eventos do WPF invoca o manipulador anexado YesNoCancelButton_Click a ele. A rota de eventos para o Click evento no exemplo é: Button ->StackPanel ->Border -> elementos pai sucessivos.

Observação

O elemento que originalmente gerou um evento roteado é identificado como nos RoutedEventArgs.Source parâmetros do manipulador de eventos. O ouvinte de eventos é o elemento em que 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 e encapsulamento do controle: vários controles no WPF têm um modelo de conteúdo avançado. 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 de teste de clique do botão, que precisa responder quando um usuário clica nos pixels da imagem.

  • Pontos de anexo do manipulador singular: você pode registrar um manipulador para o evento de Click cada botão, mas com eventos roteados você pode anexar um único manipulador, conforme mostrado no exemplo XAML anterior. Isso permite que você altere a árvore de elementos no manipulador singular, como adicionar ou remover mais botões, sem precisar registrar o evento de Click cada botão. Quando o evento é gerado, a Click 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 dão suporte a 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.

  • Referenciando um evento sem reflexão: cada evento roteado cria um identificador de RoutedEvent campo 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 com o sistema de eventos do WPF, apoiado por uma instância da classe e processado pelo sistema de RoutedEvent eventos do WPF. A RoutedEvent instância, obtida do registro, normalmente é armazenada como um public static readonly membro da classe que a registrou. Essa classe é chamada de classe "owner" do evento. Normalmente, um evento roteado implementa um evento CLR com nome idêntico "wrapper". O wrapper de eventos CLR contém add acessadores e remove para habilitar a anexação de manipuladores em XAML e no code-behind por meio da sintaxe de evento específica da linguagem. Os add acessadores and remove substituem sua implementação CLR e chamam o evento AddHandler e RemoveHandler os métodos roteados. O mecanismo de conexão e suporte de eventos roteados é conceitualmente semelhante a como uma propriedade de dependência é uma propriedade CLR apoiada pela DependencyProperty classe e registrada no sistema de propriedades do WPF.

O exemplo a seguir registra o Tap evento roteado, armazena a instância retornada RoutedEvent e implementa um wrapper de eventos 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

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

  • Blutbling: inicialmente, os manipuladores de eventos na origem do evento são invocados. Em seguida, o evento roteado é roteado 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 de propagação geralmente são usados para relatar alterações de entrada ou estado de controles compostos ou outros elementos da interface do usuário.

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

  • Direto: somente manipuladores de eventos na origem do evento são invocados. Essa estratégia de não roteamento é análoga aos eventos de 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 dão suporte à 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 importar que o evento que está manipulando é 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 lidar com eventos gerados por elementos filho, como em um controle composto.

Os ouvintes de eventos roteados não precisam que os eventos roteados que eles manipulam sejam membros de 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 oferece suporte à 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 de eventos porque cada ouvinte tem acesso à mesma instância de dados de eventos. Se um elemento alterar algo nos dados do evento, essa alteração ficará visível para os elementos subsequentes na rota do evento.

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

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

  • Os eventos roteados dão suporte a manipuladores de eventos de classe que manipulam um evento antes de qualquer manipulador de instância para o mesmo evento em qualquer instância da classe de ouvinte. Esse recurso é útil no design de controle porque o manipulador de classes pode impor comportamentos de classe controlados por eventos que não podem ser suprimidos acidentalmente por um manipulador de instâncias.

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 do ouvinte de eventos. O valor do atributo é o nome do método do manipulador. O método do manipulador deve ser implementado na classe parcial code-behind para a página XAML. O ouvinte de eventos é o elemento em que o manipulador de eventos é anexado e invocado.

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

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

Se o evento não for 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 não implementa StackPanel o Click evento, para anexar um manipulador a um StackPanel evento Click que se espalha até esse elemento, você precisará 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 do manipulador de eventos no code-behind deve corresponder ao tipo de delegado para o evento roteado. O sender parâmetro do delegado para o Click evento especifica o elemento ao qual o manipulador de RoutedEventHandler eventos está anexado. O args parâmetro do RoutedEventHandler delegado contém os dados do evento. Uma implementação code-behind compatível para o Button_Click manipulador de eventos 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 roteado, alguns controles ou cenários de implementação exigem delegados diferentes que dão suporte a dados de evento mais especializados. Por exemplo, para o DragEnter evento roteado, o manipulador deve implementar o DragEventHandler delegado. Ao fazer isso, o código do manipulador pode acessar a DragEventArgs.Data propriedade nos dados do 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 dos 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 roteado.

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 AddHandler método. Os manipuladores de eventos roteados sempre podem ser anexados dessa maneira. Este exemplo anexa um Click manipulador de eventos a um botão usando o AddHandler método:

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

    Para anexar um manipulador para o evento do Click botão a um elemento diferente na rota do evento, como um StackPanel nome StackPanel1:

    StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click));
    
    StackPanel1.[AddHandler](ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf Button_Click))
    
  • Se o evento roteado implementar um wrapper de eventos 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 existentes do WPF implementa o wrapper CLR, habilitando assim a sintaxe de evento específica da linguagem. Este exemplo anexa um Click manipulador de eventos a um botão usando a sintaxe específica da linguagem:

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

O conceito de manipulado

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

O valor de Handled afeta como um evento roteado é processado à medida que ele 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 mais adiante na rota do 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 os 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 o manipulador de eventos responda a eventos roteados que foram marcados como manipulados, você pode:

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

  • 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 ação. O evento permanece sem tratamento e é roteado para o próximo ouvinte na árvore.

    • Execute o código em resposta ao evento, mas não em uma extensão que justifique marcar o evento como manipulado. O evento permanece sem tratamento e é roteado para o próximo ouvinte na árvore.

    • Execute o código em resposta ao evento, até uma extensão que justifique marcar o evento como manipulado. Marque o evento como manipulado nos dados do evento. O evento ainda é roteado para o próximo ouvinte na árvore, mas a maioria dos ouvintes não invocará mais manipuladores. A exceção são os ouvintes com manipuladores que foram registrados especificamente com handledEventsToo set to true.

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

Embora os desenvolvedores que lidam apenas com um evento roteado de propagação 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.

Manipuladores de classe

Os manipuladores de eventos roteados 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 roteados são marcados como manipulados, eles geralmente são marcados como tal nos manipuladores de classe. Há dois tipos de manipuladores de classe:

  • Manipuladores de eventos de classe estática, que são registrados chamando o RegisterClassHandler método dentro de um construtor de classe estática.
  • Substitua os manipuladores de eventos de classe, que são registrados substituindo métodos de evento virtual de classe base. Os métodos de evento virtual de classe base existem principalmente para eventos de entrada e têm nomes que começam com o nome> do evento On<e o nome> do evento OnPreview<.

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 é gerado, mas, na realidade, ele está sendo marcado como manipulado por um manipulador de classe. Se você precisar que o manipulador de eventos responda ao evento manipulado, poderá registrar seu manipulador com handledEventsToo set to true. Para obter mais informações, tanto sobre como implementar seus próprios manipuladores de classe quanto 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 em uma classe que não seja de elemento e gerar esse evento em qualquer elemento em sua árvore. Para fazer isso, você deve registrar o evento anexado como um evento roteado e fornecer um código de suporte específico que dê 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 por seu nome de evento e tipo de proprietário, na forma de <owner type>.<event name>. Como o nome do evento é qualificado com o nome de seu tipo de proprietário, a sintaxe permite que o evento seja anexado 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 do evento. Você também pode anexar manipuladores para eventos anexados no code-behind chamando o AddHandler método no objeto ao qual o manipulador deve anexar.

O sistema de entrada do WPF usa eventos anexados extensivamente. No entanto, quase todos esses eventos anexados são exibidos como eventos roteados não anexados equivalentes por meio de elementos base. Você raramente usará ou manipulará eventos anexados diretamente. Por exemplo, é mais fácil manipular o evento anexado Mouse.MouseDown subjacente em um UIElement evento roteado equivalente UIElement.MouseDown do que usando a sintaxe de evento anexado em XAML ou 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 <owner type>.<event name> sintaxe 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 roteados 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 lidar com eventos roteados gerados em elementos filho. Se o elemento pai não tiver o evento roteado como membro, você precisará usar a sintaxe de nome de 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 roteado Click é implementado e gerado na ButtonBase classe e está disponível para a classe por meio de Button herança. Embora a Button classe "possua" o Click evento, o sistema de eventos roteados permite que manipuladores de qualquer evento roteado sejam anexados a qualquer UIElement ContentElement ouvinte de instância que, de outra forma, poderia ter manipuladores para um evento CLR. O namespace padrão xmlns para esses nomes de atributo de evento qualificados normalmente é o namespace padrão do WPF xmlns , mas você também pode especificar namespaces prefixados para eventos roteados personalizados. Para obter mais informações sobre xmlnso , consulte Namespaces XAML e mapeamento de namespace para XAML do WPF.

Eventos de entrada do WPF

Uma aplicação frequente de eventos roteados na plataforma WPF é para eventos de entrada. Por convenção, os eventos roteados do WPF que seguem uma rota de túnel têm um nome prefixado com "Preview". O prefixo Preview significa que o evento de visualização é concluído antes do início do evento de propagação emparelhado. Os eventos de entrada geralmente vêm em pares, sendo um 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 for PreviewKeyDown e KeyDown é do tipo KeyEventArgs. Ocasionalmente, os eventos de entrada têm apenas uma versão borbulhante ou apenas uma versão roteada direta. 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 para que uma única ação do usuário de um dispositivo de entrada, como pressionar um botão do mouse, gere a visualização e os eventos roteados borbulhantes em sequência. Primeiro, o evento de visualização é gerado e conclui sua rota. Após a conclusão do evento de visualização, o evento de propagação é gerado e conclui sua rota. A RaiseEvent chamada de método na classe de implementação que gera o evento de propagação reutiliza os dados do evento de 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 de propagação 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 clique 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 da árvore a seguir, leaf element #2 está a origem dos PreviewMouseDown eventos 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. PreviewMouseDown evento de tunelamento no elemento raiz.
  2. PreviewMouseDown Evento de tunelamento no elemento intermediário #1.
  3. PreviewMouseDown evento de tunelamento no elemento folha #2, que é o elemento de origem.
  4. MouseDown evento borbulhante no elemento folha #2, que é o elemento de origem.
  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 em que o manipulador foi invocado. O objeto que originalmente gerou o evento é relatado pela Source propriedade nos dados do evento. O objeto em que o manipulador foi invocado é relatado pelo parâmetro sender . 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 sim sender . Nas etapas 3 e 4 do diagrama anterior, os 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 resolver o evento, você deverá marcar o evento de entrada como manipulado. Normalmente, depois que um evento de entrada é marcado Handled, os manipuladores mais adiante na rota do evento não são invocados. No entanto, os manipuladores de eventos de entrada registrados com o handledEventsToo parâmetro definido como true serão invocados mesmo quando o evento for marcado como manipulado. Para obter mais informações, consulte Visualizar eventos e Marcar eventos roteados como manipulados e manipulação de classe.

O conceito de pares de eventos de visualização e propagação, com dados de evento compartilhados e geração sequencial do evento de visualização e, em seguida, o evento de propagação, aplica-se somente 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 lidar com 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 represente o controle completo. Para obter mais informações, consulte Marcando eventos roteados como manipulados e manipulação de classe.

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

EventSetters e EventTriggers

Em estilos de marcação, você pode incluir a 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 do manipulador de eventos referenciado ApplyButtonStyle é 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 Style nó já contenha outras informações de estilo que pertencem a controles do tipo especificado, e fazer parte desses estilos promove a EventSetter reutilização de código mesmo no nível de marcação. Além disso, um EventSetter método abstrai nomes para manipuladores longe 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. Assim como acontece com o EventSetter, você só pode declarar um EventTrigger para um evento roteado. Normalmente, an EventTrigger é declarado como parte de um estilo, mas an EventTrigger pode ser declarado em elementos de nível de página como parte da Triggers coleção ou em um ControlTemplate. An EventTrigger permite que você especifique 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 apenas EventTrigger manipular o evento e fazer com que ele inicie um storyboard existente é que an EventTrigger fornece 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 que ele é iniciado.

Mais sobre eventos roteados

Você pode usar os conceitos e as diretrizes neste artigo como 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 e delegados de dados de eventos especializados. Um proprietário de evento roteado pode ser qualquer classe, mas os eventos roteados devem ser gerados e manipulados por UIElement classes derivadas ContentElement para serem úteis. Para obter mais informações sobre eventos personalizados, consulte Criar um evento roteado personalizado.

Confira também