Předběžné události

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

Tento článek předpokládá základní znalost trasovaných událostí a že jste si přečetli přehled trasovaný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 zpracované u jiného prvku než u toho, který ji vyvolal, může zabránit prvku, který ji vyvolal, ve zpracování události. Někdy je úmyslné označit události náhledu jako vyřízené. 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 jak ve verzi náhledu, tak v ne-náhledové (bublání) verzi každé události. Pokud použijete obslužnou rutinu třídy událostí Preview k označení vstupní události jako zpracované, obslužné rutiny třídy pro bublající vstupní událost obvykle nebudou vyvolány. Nebo pokud použijete obslužnou rutinu náhledu instance události k označení události jako zpracované, instance obslužných rutin pro vstupní bublající událost 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 náhledovými událostmi, najdete v tématu Označení směrovaných událostí jako zpracovaných a zpracování tříd.

Poznámka:

Ne všechny události v ukázkové verzi jsou tunelovací události. Vstupní událost například PreviewMouseLeftButtonDown prochází stromem prvků směrem dolů, ale je to přímá směrovaná událost, která je vyvolána a znovu vyvolána každým UIElement v cestě.

Řešení potlačování událostí u ovládacích prvků

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 bublající vstupní událost jako zpracovanou 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řenu vaší aplikace zpracovávaly směrovanou událost označenou jako zpracovanou, můžete:

  • Připojte obslužné rutiny voláním UIElement.AddHandler(RoutedEvent, Delegate, Boolean) metody a nastavením parametru handledEventsToo na true. Tento přístup vyžaduje připojení obslužné rutiny události v části code-behind, po získání reference objektu na prvek, ke kterému se připojí.

  • Pokud je událost označená jako obsloužená a jedná se o bublající událost, připojte obslužné rutiny pro ekvivalentní událost 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 prvku, které implementují jak propagaci v tunelech, tak propagaci skrze bubliny 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 prvku pojmenovaného StackPanelouterStackPanel.

<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 :

  1. Označí událost směrovanou bublinou KeyDown tak, aby ji potlačovala. V důsledku toho se aktivuje pouze outerStackPanel obslužná rutina nakonfigurovaná v kódu za účelem reakce na zpracovávanéKeyDown události. Obslužná rutina outerStackPanel připojená v XAML pro KeyDown události není vyvolána.

  2. Vyvolá vlastní směrovanou událost bublinou s názvem CustomKey, která spustí obslužnou rutinu pro událost CustomKey.

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í, jak dosáhnout vyvolání obslužné rutiny události pro potlačenou směrovanou KeyDown událost připojenou k outerStackPanel:

  • Připojte obslužnou rutinu PreviewKeyDown události k outerStackPanel. Vzhledem k tomu, že směrovaná událost náhledu (Preview) předchází ekvivalentní bublající směrovanou událost, obslužná rutina v příkladu se spustí před obslužnou rutinou KeyDown, 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 události KeyDown k outerStackPanel pomocí metody UIElement.AddHandler(RoutedEvent, Delegate, Boolean) v kódu na pozadí, s parametrem handledEventsToo nastaveným na true.

Poznámka:

Označení náhledu nebo ne-náhledových ekvivalentů vstupních událostí jako zpracovaných 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é