Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Os eventos de visualização, também conhecidos como eventos de túnel, são eventos roteados que fluem pela árvore de elementos desde o elemento raiz da aplicação até o elemento que gerou o evento. O elemento que gera um evento é relatado como Source nos dados do evento. Nem todos os cenários de evento dão suporte ou exigem eventos de pré-visualização. Este artigo descreve onde os eventos de visualização existem e como aplicativos ou componentes podem interagir com eles. Para obter informações sobre como criar um evento de visualização, consulte Como criar um evento roteado personalizado.
Pré-requisitos
O artigo pressupõe um conhecimento básico dos eventos roteados e que você leu Visão Geral de Eventos Roteados. Para seguir os exemplos neste artigo, ele ajuda se você estiver familiarizado com XAML (Extensible Application Markup Language) e saber como escrever aplicativos do WPF (Windows Presentation Foundation).
Visualizar eventos marcados como processados
Tenha cuidado ao marcar eventos de visualização como tratados nas informações do evento. Marcar um evento de visualização como manipulado em um elemento diferente do elemento que o gerou pode impedir que o elemento que o gerou manipule o evento. Às vezes, marcar eventos de visualização como já tratados é intencional. Por exemplo, um controle composto pode suprimir eventos gerados por componentes individuais e substituí-los por eventos gerados pelo controle completo. Eventos personalizados para um controle podem fornecer dados de evento personalizados e gatilho com base nas relações de estado do componente.
Para eventos de entrada, os dados do evento são compartilhados tanto pelos equivalentes em modo de visualização quanto pelos de não visualização (bubbling) de cada evento. Se você usar um manipulador de classe de evento de visualização para marcar um evento de entrada como manipulado, os manipuladores de classe para o evento de entrada borbulhante normalmente não serão invocados. Ou, se você usar um manipulador de pré-visualização para marcar um evento como manipulado, os manipuladores de instância para o evento de entrada borbulhante normalmente não serão invocados. Embora você possa configurar manipuladores de classe e instância para serem invocados mesmo que um evento seja marcado como manipulado, essa configuração de manipulador não é comum. Para obter mais informações sobre o tratamento de classe e como ele se relaciona com eventos de visualização, consulte Marcar eventos roteados como manipulados e tratar eventos por classe.
Observação
Nem todos os eventos de visualização são eventos tunneling. Por exemplo, o PreviewMouseLeftButtonDown evento de entrada segue uma rota para baixo através da árvore de elementos, mas é um evento roteado direto que é gerado e levantado novamente por cada elemento UIElement na rota.
Trabalhando em torno da supressão de eventos por controles
Alguns controles compostos suprimem eventos de entrada no nível do componente para substituí-los por um evento personalizado de alto nível. Por exemplo, o WPF ButtonBase marca o MouseLeftButtonDown evento de entrada de borbulha conforme tratado em seu OnMouseLeftButtonDown método e gera o Click evento. O MouseLeftButtonDown evento e seus dados de evento ainda continuam ao longo da rota da árvore de elementos, mas como o evento está marcado como Handled em dados de evento, apenas manipuladores configurados para responder a eventos manipulados são invocados.
Se você quiser que outros elementos na raiz do aplicativo manipulem um evento roteado marcado como manipulado, você pode:
Anexar manipuladores chamando o UIElement.AddHandler(RoutedEvent, Delegate, Boolean) método e definindo o parâmetro
handledEventsToocomotrue. Essa abordagem requer anexar o manipulador de eventos no code-behind, depois de obter uma referência de objeto ao elemento ao qual ele será anexado.Se o evento marcado como manipulado for um evento de bolhas, anexe manipuladores para o evento de visualização equivalente, se disponível. Por exemplo, se um controle suprimir o MouseLeftButtonDown evento, você poderá anexar um manipulador para o PreviewMouseLeftButtonDown evento. Essa abordagem funciona apenas para eventos de entrada de elemento base que implementam estratégias de roteamento de túnel e borbulhamento e que compartilhem dados de eventos.
O exemplo a seguir implementa um controle personalizado rudimentar chamado componentWrapper que contém um TextBox. O controle é adicionado a um StackPanel chamado outerStackPanel.
<StackPanel Name="outerStackPanel"
VerticalAlignment="Center"
custom:ComponentWrapper.CustomKey="Handler_PrintEventInfo"
TextBox.KeyDown="Handler_PrintEventInfo"
TextBox.PreviewKeyDown="Handler_PrintEventInfo" >
<custom:ComponentWrapper
x:Name="componentWrapper"
TextBox.KeyDown="ComponentWrapper_KeyDown"
custom:ComponentWrapper.CustomKey="Handler_PrintEventInfo"
HorizontalAlignment="Center">
<TextBox Name="componentTextBox" Width="200" KeyDown="Handler_PrintEventInfo" />
</custom:ComponentWrapper>
</StackPanel>
O componentWrapper controle escuta o KeyDown evento de borbulha gerado por seu TextBox componente sempre que ocorre um pressionamento de tecla. Nessa ocorrência, o componentWrapper controle:
Marca o
KeyDownevento de propagação como manipulado para suprimir sua propagação. Como resultado, somente oouterStackPanelmanipulador configurado em code-behind para responder a eventos manipuladosKeyDowné acionado. O manipuladorouterStackPanelanexado para eventosKeyDownem XAML não é invocado.Gera um evento roteado de propagação personalizado chamado
CustomKey, que dispara o manipuladorouterStackPanelpara o eventoCustomKey.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Attach a handler on outerStackPanel that will be invoked by handled KeyDown events.
outerStackPanel.AddHandler(KeyDownEvent, new RoutedEventHandler(Handler_PrintEventInfo),
handledEventsToo: true);
}
private void ComponentWrapper_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
Handler_PrintEventInfo(sender, e);
Debug.WriteLine("KeyDown event marked as handled on componentWrapper.\r\n" +
"CustomKey event raised on componentWrapper.");
// Mark the event as handled.
e.Handled = true;
// Raise the custom click event.
componentWrapper.RaiseCustomRoutedEvent();
}
private void Handler_PrintEventInfo(object sender, System.Windows.Input.KeyEventArgs e)
{
string senderName = ((FrameworkElement)sender).Name;
string sourceName = ((FrameworkElement)e.Source).Name;
string eventName = e.RoutedEvent.Name;
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
Debug.WriteLine($"Handler attached to {senderName} " +
$"triggered by {eventName} event raised on {sourceName}.{handledEventsToo}");
}
private void Handler_PrintEventInfo(object sender, RoutedEventArgs e)
{
string senderName = ((FrameworkElement)sender).Name;
string sourceName = ((FrameworkElement)e.Source).Name;
string eventName = e.RoutedEvent.Name;
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
Debug.WriteLine($"Handler attached to {senderName} " +
$"triggered by {eventName} event raised on {sourceName}.{handledEventsToo}");
}
// Debug output:
//
// Handler attached to outerStackPanel triggered by PreviewKeyDown event raised on componentTextBox.
// Handler attached to componentTextBox triggered by KeyDown event raised on componentTextBox.
// Handler attached to componentWrapper triggered by KeyDown event raised on componentTextBox.
// KeyDown event marked as handled on componentWrapper.
// CustomKey event raised on componentWrapper.
// Handler attached to componentWrapper triggered by CustomKey event raised on componentWrapper.
// Handler attached to outerStackPanel triggered by CustomKey event raised on componentWrapper.
// Handler attached to outerStackPanel triggered by KeyDown event raised on componentTextBox. Parameter handledEventsToo set to true.
}
public class ComponentWrapper : StackPanel
{
// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent CustomKeyEvent =
EventManager.RegisterRoutedEvent(
name: "CustomKey",
routingStrategy: RoutingStrategy.Bubble,
handlerType: typeof(RoutedEventHandler),
ownerType: typeof(ComponentWrapper));
// Provide CLR accessors for assigning an event handler.
public event RoutedEventHandler CustomKey
{
add { AddHandler(CustomKeyEvent, value); }
remove { RemoveHandler(CustomKeyEvent, value); }
}
public void RaiseCustomRoutedEvent()
{
// Create a RoutedEventArgs instance.
RoutedEventArgs routedEventArgs = new(routedEvent: CustomKeyEvent);
// Raise the event, which will bubble up through the element tree.
RaiseEvent(routedEventArgs);
}
}
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
' Attach a handler on outerStackPanel that will be invoked by handled KeyDown events.
outerStackPanel.[AddHandler](KeyDownEvent, New RoutedEventHandler(AddressOf Handler_PrintEventInfo),
handledEventsToo:=True)
End Sub
Private Sub ComponentWrapper_KeyDown(sender As Object, e As KeyEventArgs)
Handler_PrintEventInfo(sender, e)
Debug.WriteLine("KeyDown event marked as handled on componentWrapper." &
vbCrLf & "CustomKey event raised on componentWrapper.")
' Mark the event as handled.
e.Handled = True
' Raise the custom click event.
componentWrapper.RaiseCustomRoutedEvent()
End Sub
Private Sub Handler_PrintEventInfo(sender As Object, e As KeyEventArgs)
Dim senderName As String = CType(sender, FrameworkElement).Name
Dim sourceName As String = CType(e.Source, FrameworkElement).Name
Dim eventName As String = e.RoutedEvent.Name
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
Debug.WriteLine($"Handler attached to {senderName} " &
$"triggered by {eventName} event raised on {sourceName}.{handledEventsToo}")
End Sub
Private Sub Handler_PrintEventInfo(sender As Object, e As RoutedEventArgs)
Dim senderName As String = CType(sender, FrameworkElement).Name
Dim sourceName As String = CType(e.Source, FrameworkElement).Name
Dim eventName As String = e.RoutedEvent.Name
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
Debug.WriteLine($"Handler attached to {senderName} " &
$"triggered by {eventName} event raised on {sourceName}.{handledEventsToo}")
End Sub
' Debug output
'
' Handler attached to outerStackPanel triggered by PreviewKeyDown event raised on componentTextBox.
' Handler attached to componentTextBox triggered by KeyDown event raised on componentTextBox.
' Handler attached to componentWrapper triggered by KeyDown event raised on componentTextBox.
' KeyDown event marked as handled on componentWrapper.
' CustomKey event raised on componentWrapper.
' Handler attached to componentWrapper triggered by CustomKey event raised on componentWrapper.
' Handler attached to outerStackPanel triggered by CustomKey event raised on componentWrapper.
' Handler attached to outerStackPanel triggered by KeyDown event raised on componentTextBox. Parameter handledEventsToo set to true.
End Class
Public Class ComponentWrapper
Inherits StackPanel
' Register a custom routed event with the Bubble routing strategy.
Public Shared ReadOnly CustomKeyEvent As RoutedEvent =
EventManager.RegisterRoutedEvent(
name:="CustomKey",
routingStrategy:=RoutingStrategy.Bubble,
handlerType:=GetType(RoutedEventHandler),
ownerType:=GetType(ComponentWrapper))
' Provide CLR accessors to support event handler assignment.
Public Custom Event CustomKey As RoutedEventHandler
AddHandler(value As RoutedEventHandler)
[AddHandler](CustomKeyEvent, value)
End AddHandler
RemoveHandler(value As RoutedEventHandler)
[RemoveHandler](CustomKeyEvent, value)
End RemoveHandler
RaiseEvent(sender As Object, e As RoutedEventArgs)
[RaiseEvent](e)
End RaiseEvent
End Event
Public Sub RaiseCustomRoutedEvent()
' Create a RoutedEventArgs instance & raise the event,
' which will bubble up through the element tree.
Dim routedEventArgs As New RoutedEventArgs(routedEvent:=CustomKeyEvent)
[RaiseEvent](routedEventArgs)
End Sub
End Class
O exemplo demonstra duas soluções alternativas para obter o evento roteado suprimido KeyDown para invocar um manipulador de eventos anexado ao outerStackPanel:
Anexar um PreviewKeyDown manipulador de eventos ao
outerStackPanel. Como um evento roteado de entrada de pré-visualização precede o evento roteado de propagação equivalente, o manipuladorPreviewKeyDownno exemplo é executado antes do manipuladorKeyDown, que suprime ambos os eventos de pré-visualização e de propagação por meio de seus dados de evento compartilhados.Anexe um
KeyDownmanipulador de eventos aoouterStackPanelusando o método UIElement.AddHandler(RoutedEvent, Delegate, Boolean) no code-behind, com o parâmetrohandledEventsTooconfigurado paratrue.
Observação
Marcar os equivalentes de visualização ou não visualização de eventos de entrada como manipulados são estratégias para suprimir eventos gerados pelos componentes de um controle. A abordagem usada depende dos requisitos do aplicativo.
Consulte também
.NET Desktop feedback