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:
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 eventoClick
de cada botão. Quando o eventoClick
é 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 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étodoAddHandler
: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 chamadoStackPanel1
: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:
Anexe o manipulador no código subjacente usando a sobrecarga AddHandler(RoutedEvent, Delegate, Boolean), com o parâmetro
handledEventsToo
definido comotrue
.Defina o atributo HandledEventsToo em um
EventSetter
comotrue
.
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 comotrue
.
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:
- Manipuladores de eventos de classe estática, que são registrados chamando o método RegisterClassHandler dentro de um construtor de classe estática.
-
Substituir os manipuladores de eventos da classe, que são registados ao substituir os métodos de eventos virtuais da classe base. Os métodos de evento virtual da classe base existem principalmente para eventos de entrada e têm nomes que começam com On
e OnPreview de nome de evento .
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:
A ordem de processamento de eventos após uma ação de mouse para baixo no elemento folha #2 é:
- Evento de tunelamento
PreviewMouseDown
no elemento raiz. -
PreviewMouseDown
evento de tunelamento no elemento intermediário #1. -
PreviewMouseDown
evento de tunelização no elemento folha #2, que é o elemento fonte. -
MouseDown
evento borbulhante no elemento folha #2, que é o elemento fonte. -
MouseDown
evento borbulhante no elemento intermediário #1. -
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
.NET Desktop feedback