Události ve verzi Preview (WPF .NET)
Události verze Preview, označované také jako události tunelování, jsou směrované události, které procházejí stromem elementů z kořenového prvku aplikace do elementu, který vyvolal událost. Prvek, který vyvolá událost, je hlášen jako Source v datech události. Ne všechny scénáře událostí podporují nebo vyžadují události ve verzi Preview. Tento článek popisuje, kde existují události ve verzi Preview a jak s nimi můžou aplikace nebo komponenty pracovat. Informace o tom, jak vytvořit událost ve verzi Preview, najdete v tématu Vytvoření vlastní směrované události.
Požadavky
V článku se předpokládá základní znalost směrovaných událostí a že jste si přečetli přehled směrovaných událostí. Pokud chcete postupovat podle příkladů v tomto článku, pomůže vám to, pokud znáte jazyk XAML (Extensible Application Markup Language) a víte, jak psát aplikace WINDOWS Presentation Foundation (WPF).
Náhled událostí označených jako zpracovávané
Při označování událostí náhledu jako zpracovaných v datech událostí buďte opatrní. Označení události náhledu jako zpracovávané u jiného prvku, než je prvek, který ho vyvolal, může zabránit prvku, který ho vyvolal v zpracování události. Někdy je označení událostí náhledu úmyslné. Složený ovládací prvek může například potlačit události vyvolané jednotlivými komponentami a nahradit je událostmi vyvolanými úplným ovládacím prvku. Vlastní události ovládacího prvku můžou poskytovat přizpůsobená data událostí a triggery na základě relací stavu součástí.
U vstupních událostí jsou data událostí sdílena ekvivalenty jednotlivých událostí ve verzi Preview i bez náhledu (bublání). Pokud použijete obslužnou rutinu třídy událostí ve verzi Preview k označení vstupní události jako obslužné rutiny, obslužné rutiny třídy pro vstupní událost bublání obvykle nebudou vyvolány. Nebo pokud použijete obslužnou rutinu instance události ve verzi Preview k označení události jako obslužné rutiny, obslužné rutiny instance pro vstupní událost bublání obvykle nebudou vyvolány. I když můžete nakonfigurovat obslužné rutiny třídy a instance tak, aby byly vyvolány i v případě, že je událost označena jako zpracována, tato konfigurace obslužné rutiny není běžná. Další informace o zpracování tříd a o tom, jak souvisí s událostmi verze Preview, najdete v tématu Označení směrovaných událostí jako zpracovávaných a zpracování tříd.
Poznámka:
Ne všechny události ve verzi Preview jsou události tunelování . Vstupní událost se například PreviewMouseLeftButtonDown řídí dolů přes strom prvků, ale je to přímá směrovaná událost, která je vyvolána a reraizována každou UIElement trasou v trase.
Práce s potlačením událostí ovládacími prvky
Některé složené ovládací prvky potlačí vstupní události na úrovni komponenty, aby je nahradily přizpůsobenou událostí vysoké úrovně. WpF ButtonBase například označí MouseLeftButtonDown vstupní událost bublajícího vstupu, jak je zpracována ve své OnMouseLeftButtonDown metodě, a vyvolá Click událost. Událost MouseLeftButtonDown
a její data události stále pokračují podél trasy stromu prvků, ale protože událost je označena jako Handled v datech událostí, jsou vyvolány pouze obslužné rutiny nakonfigurované tak, aby reagovaly na zpracovávané události.
Pokud chcete, aby ostatní prvky směrem ke kořenovému adresáři vaší aplikace zpracovávaly směrovanou událost označenou jako popisovanou, můžete:
Připojte obslužné rutiny voláním UIElement.AddHandler(RoutedEvent, Delegate, Boolean) metody a nastavením parametru
handledEventsToo
natrue
. Tento přístup vyžaduje připojení obslužné rutiny události v kódu za sebou, po získání odkazu objektu na prvek, ke kterému se připojí.Pokud je událost označená jako obslužná událost bublající událost, připojte obslužné rutiny ekvivalentní události náhledu, pokud jsou k dispozici. Pokud například ovládací prvek potlačí MouseLeftButtonDown událost, můžete místo toho připojit obslužnou rutinu PreviewMouseLeftButtonDown události. Tento přístup funguje pouze u vstupních událostí základního elementu, které implementují strategie směrování tunelování i bublinové směrování a sdílejí data událostí.
Následující příklad implementuje základní vlastní ovládací prvek s názvem componentWrapper
, který obsahuje TextBox. Ovládací prvek se přidá do pojmenovaného StackPanel 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>
Ovládací componentWrapper
prvek naslouchá KeyDown události bublání vyvolané jeho TextBox
komponentou při každém stisknutí klávesy. V takovém případě ovládací prvek componentWrapper
:
Označí událost směrovanou bublinou
KeyDown
tak, aby ji potlačovala. V důsledku toho se aktivuje pouzeouterStackPanel
obslužná rutina nakonfigurovaná v kódu za účelem reakce na zpracovávanéKeyDown
události. Obslužná rutinaouterStackPanel
připojená v XAML proKeyDown
události není vyvolána.Vyvolá vlastní událost směrovanou bublinou s názvem
CustomKey
, která aktivuje obslužnou rutinuouterStackPanel
CustomKey
události.
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
Příklad ukazuje dvě alternativní řešení pro získání potlačené směrované KeyDown
události vyvolat obslužnou rutinu události připojenou k outerStackPanel
:
Připojte obslužnou rutinu PreviewKeyDown události k sadě
outerStackPanel
. Vzhledem k tomu,PreviewKeyDown
že vstupní událost směrovaná ve verzi Preview předchází ekvivalentní směrované události, obslužná rutina v příkladu se spustí předKeyDown
obslužnou rutinou, která potlačuje události náhledu i bublání prostřednictvím jejich sdílených dat událostí.Připojte obslužnou rutinu
KeyDown
outerStackPanel
události pomocí UIElement.AddHandler(RoutedEvent, Delegate, Boolean) metody v kódu na pozadí s parametrem nastavenýmhandledEventsToo
natrue
.
Poznámka:
Označení náhledu nebo ekvivalentů vstupních událostí, které nejsou ve verzi Preview, jsou obě strategie potlačení událostí vyvolaných komponentami ovládacího prvku. Přístup, který používáte, závisí na požadavcích vaší aplikace.
Viz také
.NET Desktop feedback