Olayları önizleme (WPF .NET)

Tünel olayları olarak da bilinen önizleme olayları, uygulama kök öğesinden olayı tetikleyen öğeye öğe ağacı boyunca aşağı doğru geçen yönlendirilmiş olaylardır. Olay oluşturan öğesi, olay verilerinde olarak Source bildirilir. Tüm olay senaryoları önizleme olaylarını desteklemez veya gerektirmez. Bu makalede önizleme olaylarının nerede olduğu ve uygulamaların veya bileşenlerin bunlarla nasıl etkileşim kurabileceği açıklanmaktadır. Önizleme olayı oluşturma hakkında bilgi için bkz . Özel yönlendirilmiş olay oluşturma.

Önkoşullar

Makalede, yönlendirilen olaylar hakkında temel bilgiler edindiğiniz ve Yönlendirilen olaylara genel bakış makalesini okuduğunuz varsayılır. Bu makaledeki örnekleri takip etmek için, Genişletilebilir Uygulama biçimlendirme dili (XAML) hakkında bilgi sahibi olmanız ve Windows Presentation Foundation (WPF) uygulamalarının nasıl yazıldığından haberdar olmanız yardımcı olur.

İşlendi olarak işaretlenmiş olayları önizleme

Önizleme olaylarını olay verilerinde işlenecek şekilde işaretlerken dikkatli olun. Bir önizleme olayını yükselten öğe dışındaki bir öğede işlenmek üzere işaretlemek, onu yükselten öğenin olayı işlemesini engelleyebilir. Bazen önizleme olaylarının işlendiğinde işaretlenmesi kasıtlı olarak gerçekleştirilir. Örneğin, bileşik denetim tek tek bileşenler tarafından tetiklenen olayları bastırabilir ve bunları tam denetim tarafından tetiklenen olaylarla değiştirebilir. Denetim için özel olaylar, bileşen durumu ilişkilerine göre özelleştirilmiş olay verileri ve tetikleyici sağlayabilir.

Giriş olayları için olay verileri, her olayın hem önizleme hem de önizleme dışı (kabarcık oluşturma) eşdeğerleri tarafından paylaşılır. Bir giriş olayını işlenmiş olarak işaretlemek için bir önizleme olayı sınıf işleyicisi kullanırsanız, kabarcık oluşturma giriş olayı için sınıf işleyicileri genellikle çağrılamaz. Öte yandan, bir olayı işlenmiş olarak işaretlemek için bir önizleme olay örneği işleyicisi kullanırsanız, kabarcık giriş olayının örnek işleyicileri genellikle çağrılmazsınız. Bir olay işlendi olarak işaretlenmiş olsa bile çağrılacak sınıf ve örnek işleyicilerini yapılandırabilirsiniz ancak bu işleyici yapılandırması yaygın değildir. Sınıf işleme ve önizleme olaylarıyla ilişkisi hakkında daha fazla bilgi için bkz . Yönlendirilen olayları işlenmiş olarak işaretleme ve sınıf işleme.

Not

Önizleme olaylarının tümü olayları tünellemez. Örneğin, PreviewMouseLeftButtonDown giriş olayı öğe ağacı boyunca aşağı doğru bir yol izler, ancak yoldaki her UIElement biri tarafından tetiklenen ve yeniden değerlendirilen doğrudan yönlendirilmiş bir olaydır.

Denetimler tarafından olay gizlemeyi geçici olarak çözme

Bazı bileşik denetimler, özelleştirilmiş bir üst düzey olayla değiştirmek için bileşen düzeyinde giriş olaylarını gizler. Örneğin, WPF ButtonBase kabarcık giriş olayını yönteminde OnMouseLeftButtonDown işlenmiş olarak işaretler MouseLeftButtonDown ve olayı tetiklerClick. Olay MouseLeftButtonDown ve olay verileri öğe ağacı yolu boyunca devam eder, ancak olay olay verilerinde olarak Handled işaretlendiğinden, yalnızca işlenen olaylara yanıt verecek şekilde yapılandırılmış işleyiciler çağrılır.

Uygulamanızın köküne yönelik diğer öğelerin işlendi olarak işaretlenmiş yönlendirilmiş bir olayı işlemesini istiyorsanız şunlardan birini yapabilirsiniz:

  • yöntemini çağırarak ve parametresini UIElement.AddHandler(RoutedEvent, Delegate, Boolean) handledEventsToo trueolarak ayarlayarak işleyicileri ekleyin. Bu yaklaşım, ekleyecek öğeye bir nesne başvurusu aldıktan sonra olay işleyicisinin arka planda koda eklenmesini gerektirir.

  • İşlendi olarak işaretlenen olay bir kabarcık olayıysa, varsa eşdeğer önizleme olayı için işleyiciler ekleyin. Örneğin, bir denetim olayı bastırıyorsa MouseLeftButtonDown , bunun yerine olay için PreviewMouseLeftButtonDown bir işleyici ekleyebilirsiniz. Bu yaklaşım yalnızca hem tünel hem de kabarcık yönlendirme stratejileri uygulayan ve olay verilerini paylaşan temel öğe giriş olayları için çalışır.

Aşağıdaki örnek, öğesini içeren TextBoxadlı componentWrapper bir ilkel özel denetim uygular. Denetim adlı outerStackPanelbir StackPanel öğesine eklenir.

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

Denetim, componentWrapper bir tuş vuruşu gerçekleştiğinde KeyDown bileşeni tarafından TextBox tetiklenen kabarcık olayını dinler. Bu durumla ilgili componentWrapper denetim:

  1. Kabarcıklanan KeyDown yönlendirilmiş olayı, gizlenmek için işlenme olarak işaretler. Sonuç olarak, yalnızca outerStackPanel işlenen KeyDown olaylara yanıt vermek için arka planda kod içinde yapılandırılmış işleyici tetiklenmiş olur. outerStackPanel Olaylar için KeyDown XAML'ye eklenen işleyici çağrılmıyor.

  2. adlı CustomKeyözel bir kabarcıklama yönlendirilmiş olayı oluşturur ve bu olay işleyicisini outerStackPanel CustomKey tetikler.

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

Örnekte, öğesine bağlı bir olay işleyicisini çağırmak için gizlenen yönlendirilmiş KeyDown olayı almak için iki geçici çözüm gösterilmektedir outerStackPanel:

  • öğesine bir PreviewKeyDown olay işleyicisi outerStackPanelekleyin. Bir önizleme girişi yönlendirilmiş olay eşdeğer kabarcık yönlendirilmiş olayından önce olduğundan, örnekteki işleyici, PreviewKeyDown paylaşılan olay verileri aracılığıyla hem önizleme hem de kabarcık oluşturma olaylarını bastıran işleyicinin KeyDown önünde çalışır.

  • parametresi olarak ayarlanmış truearka planda handledEventsToo yöntemini kullanarak UIElement.AddHandler(RoutedEvent, Delegate, Boolean) öğesine bir KeyDown olay işleyicisi outerStackPanel ekleyin.

Not

Giriş olaylarının önizleme veya önizleme dışı eşdeğerlerinin işlenmek üzere işaretlenmesi, denetimin bileşenleri tarafından oluşturulan olayları gizlemeye yönelik stratejilerdir. Kullandığınız yaklaşım, uygulama gereksinimlerinize bağlıdır.

Ayrıca bkz.