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

Os desenvolvedores de aplicativos do Windows Presentation Foundation (WPF) e os autores de componentes 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 orientação sobre quando e como responder a eventos roteados.

Importante

A documentação do Guia da Área de Trabalho para .NET 7 e .NET 6 está em construção.

Pré-requisitos

Este artigo pressupõe um conhecimento básico do Common Language Runtime (CLR), programação orientada a objetos e como o layout de 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 fonte 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 WPF, apoiado por uma instância da RoutedEvent classe e processado pelo sistema de eventos 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 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:

  • Borbulha através da árvore de elementos do elemento de origem para o elemento raiz, que normalmente é uma página ou janela.
  • Tuneliza a á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:

Yes, No, and Cancel buttons.

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

Observação

O elemento que gerou originalmente um evento roteado é identificado como os RoutedEventArgs.Source 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 e encapsulamento de controle: Vários controles no WPF têm um modelo de conteúdo rico. Por exemplo, você pode colocar uma imagem dentro de um Button, 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 anexo do manipulador singular: você pode registrar um manipulador para cada evento do botão, mas com eventos roteados Click você pode 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 de Click cada botão. Quando o evento é gerado, a lógica do manipulador pode determinar de onde o Click 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
    
  • Tratamento de classe: os eventos roteados oferecem 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.

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

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

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

  • Borbulhamento: inicialmente, os manipuladores de eventos na origem do evento são chamados. O evento roteado então roteia 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. 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.

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

  • Direto: somente manipuladores de eventos na fonte de eventos são chamados. Essa estratégia que não é de 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 diretamente oferecem suporte à manipulação de classes 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 você está manipulando seja implementado como um evento roteado. Os eventos roteados têm um comportamento especial, mas esse comportamento é em grande parte 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 dos eventos roteados que manipulam para serem membros de sua classe. Qualquer UIElement ou ContentElement pode ser um ouvinte de eventos para qualquer evento roteado. Como os elementos visuais derivam de ou ContentElement, você pode usar eventos roteados como uma "interface" conceitual que oferece suporte à troca de informações de UIElement eventos entre elementos diferentes em um aplicativo. O conceito de "interface" para eventos roteados é particularmente aplicável a eventos de entrada.

Os eventos roteados oferecem suporte à troca de informações de evento entre elementos ao longo da rota do evento porque cada ouvinte tem acesso à mesma instância de dados de evento. 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 pelos seguintes 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 oferecem 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 seu manipulador de classe pode impor comportamentos de classe orientados a 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 do evento. O valor do atributo é o nome do método 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 é 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 o Click evento, para anexar um manipulador a um StackPanel evento Click que borbulha até esse elemento, você precisará usar a StackPanel 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 em code-behind deve corresponder ao tipo de delegado para o evento roteado. O sender parâmetro do delegado para o evento especifica o elemento ao qual o Click manipulador de RoutedEventHandler eventos está anexado. O args parâmetro do delegado contém os dados do RoutedEventHandler 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 representante 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 roteado, o manipulador deve implementar o DragEnterDragEventHandler delegado. Ao fazer isso, o código do manipulador pode acessar a propriedade nos dados do evento, que contém a DragEventArgs.Data carga útil 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 manipulador de eventos a um Click 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 botão a um elemento diferente na rota do Click 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 evento CLR, use a sintaxe de evento específica do idioma para adicionar manipuladores de eventos da mesma forma que faria para um evento CLR padrão. A maioria dos eventos roteados WPF existentes implementa o wrapper CLR, habilitando assim a sintaxe de eventos específicos da linguagem. Este exemplo anexa um manipulador de eventos a um Click botão usando sintaxe específica de 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, você também pode usar a Handles palavra-chave para adicionar manipuladores como parte das declarações de manipulador. Para obter mais informações, consulte Tratamento de eventos do Visual Basic e WPF.

O conceito de manuseado

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 . O objetivo da propriedade é permitir que qualquer manipulador de eventos ao longo da rota de eventos marque o evento roteado Handled como manipulado. Para marcar um evento como manipulado, defina o valor de para true no código do manipulador de Handled eventos.

O valor de afeta como um evento roteado é processado à medida que viaja ao longo da rota do Handled 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 chamados 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 de 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 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 for marcado como manipulado, os ouvintes anteriores na rota de eventos não terão um manipulador para o evento ou nenhum dos manipuladores registrados respondeu ao evento de uma maneira 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 atitude. O evento permanece sem tratamento e é encaminhado para o próximo ouvinte na árvore.

    • Execute 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 é encaminhado para o próximo ouvinte na árvore.

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

Para obter mais informações sobre como manipular eventos roteados, consulte Marcando eventos roteados como manipulados e Tratamento de classe.

Embora os desenvolvedores que lidam apenas com 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 ao longo da rota de 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 chamados antes de qualquer manipulador de instância responder ao mesmo evento em qualquer instância dessa classe. Devido a esse comportamento, quando eventos roteados são marcados como manipulados, eles geralmente são marcados como tal dentro de 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 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 On event name e OnPreview<<event name>>.

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, 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 o manipulador com handledEventsToo o conjunto .true Para obter mais informações, tanto sobre como implementar seus próprios manipuladores de classe quanto para contornar o tratamento indesejado de classes, consulte Marcando eventos roteados como manipulados e Tratamento 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 da árvore. Para fazer isso, você deve registrar o evento anexado como um evento roteado 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 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 de eventos. Você também pode anexar manipuladores para eventos anexados no code-behind chamando o AddHandler método no objeto ao qual o manipulador deve se 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 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 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 manipular 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 StackPanelarquivo . No entanto, o evento roteado Click é implementado e gerado na ButtonBase classe e disponível para a Button classe por meio de herança. Embora a classe "possua" o evento, o Click sistema de eventos roteado permite que os manipuladores de qualquer evento roteado sejam anexados a Button qualquer UIElement ouvinte de instância que, de ContentElement outra forma, poderia ter manipuladores para um evento CLR. O namespace padrão para esses nomes de atributo de evento qualificados normalmente é o namespace WPF xmlns padrãoxmlns, 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 roteados do WPF que seguem uma rota de encapsulamento 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 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 para que uma única ação do usuário de um dispositivo de entrada, como pressionar o botão do mouse, aumente 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 borbulhante é gerado e completa sua rota. A RaiseEvent chamada de método na classe de implementação que gera o evento borbulhante reutiliza os dados do evento de visualização para o evento borbulhante.

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 impacto 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 o processamento de eventos de entrada funciona, considere o exemplo de evento de entrada a seguir. Na ilustração de árvore a seguir, leaf element #2 é a fonte dos PreviewMouseDown eventos e MouseDown emparelhados:

Event routing diagram.

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

  1. PreviewMouseDown Evento de encapsulamento no elemento raiz.
  2. PreviewMouseDown Evento de encapsulamento no elemento intermediário #1.
  3. PreviewMouseDown Evento de encapsulamento 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 borbulhante no elemento raiz.

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

Se o manipulador de eventos de entrada concluir a lógica específica do aplicativo necessária para endereçar o evento, você deverá marcar o evento de entrada como manipulado. Normalmente, depois que um evento de entrada é marcado Handled, os manipuladores mais adiante ao longo da rota do evento não são invocados. No entanto, os manipuladores de eventos de entrada registrados com o parâmetro definido como serão chamados mesmo quando o handledEventsToo evento for marcado como true manipulado. Para obter mais informações, consulte Visualizar eventos e Marcar eventos roteados como manipulados e Tratamento de classe.

O conceito de pares de eventos de visualização e borbulhamento, com dados de eventos compartilhados e aumento sequencial do evento de visualização e, em seguida, do evento borbulhante, 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 resolver 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 Tratamento de classe.

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.

EventSetters e EventTriggers

Em estilos de marcação, você pode incluir sintaxe de manipulação de eventos XAML pré-declarada usando um EventSetterarquivo . Quando o XAML é processado, o manipulador referenciado é adicionado à instância estilizada. Você só pode declarar um para um EventSetter evento roteado. No exemplo a seguir, o método de manipulador de eventos referenciado ApplyButtonStyle é implementado em 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ó já contenha outras informações de estilo que pertençam a controles do tipo especificado, e ter o Style ser 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 de resumos nomeia para manipuladores longe do aplicativo geral e da marcação de página.

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

Mais sobre eventos roteados

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

Confira também