Önizleme etkinlikleri

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 bilgilere sahip olduğunuz 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ı, onu tetikleyen öğe dışındaki bir öğede işlenmiş olarak işaretlemek, olayın tetikleyen öğe tarafından işlenmesini engelleyebilir. Bazen önizleme olaylarının işaretlenmesi kasıtlı olarak yapılır. Ö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. Veya 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ılmaz. 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şlemesi ve önizleme etkinlikleriyle nasıl ilişkilendirildiği hakkında daha fazla bilgi için bkz Yönlendirilmiş olayları işlenmiş olarak işaretleme ve sınıf işlemesi.

Uyarı

Tüm önizleme olayları tünel olayları değildir. Örneğin, PreviewMouseLeftButtonDown giriş olayı, öğe ağacı boyunca aşağıya doğru bir yol izler, ancak her rotadaki tarafından tetiklenen ve yeniden tetiklenen bir doğrudan UIElement yönlendirilmiş 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 taşınan giriş olayını MouseLeftButtonDown yönteminde işlenmiş olarak işaretler ve Click olayını tetiklerOnMouseLeftButtonDown. Olay MouseLeftButtonDown ve olay verileri öğe ağacı yolu boyunca devam eder, ancak olay verilerinde Handled olarak işaretlendiğinden, yalnızca işlenmiş olaylara yanıt verecek şekilde yapılandırılmış işleyiciler çağrılır.

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

  • UIElement.AddHandler(RoutedEvent, Delegate, Boolean) yöntemini çağırarak ve handledEventsToo parametresini true olarak ayarlayarak işleyicileri ekleyin. Bu yaklaşım, ekleneceği öğeye bir nesne başvurusu alındıktan sonra, olay işleyicisinin kodun arka planında 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 MouseLeftButtonDown olayını bastırıyorsa, bu durumda PreviewMouseLeftButtonDown olayı için bir işleyici ekleyebilirsiniz. Bu yaklaşım yalnızca hem tünelleme hem de kabarcık yönlendirme stratejilerini uygulayan ve olay verilerini paylaşan temel öğe giriş olayları için çalışır.

Aşağıdaki örnek, TextBox öğesini içeren componentWrapper adlı ilkel bir özel denetim uygular. StackPanel adına sahip outerStackPanel kontrolüne 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>

componentWrapper denetimi, tuş vuruşu gerçekleştiğinde TextBox bileşeni tarafından tetiklenen KeyDown yayılma olayını dinler. Bu durum gerçekleştiğinde componentWrapper denetim:

  1. Yükselen KeyDown yönlendirilmiş olayı baskılamak için 'işlenmiş' olarak işaretler. Sonuç olarak, yalnızca outerStackPanel işlenmiş olaylara yanıt vermek için arka plandaki kodda yapılandırılmış işleyici tetiklenir. KeyDown olaylarını işleyen ve XAML'ye eklenen outerStackPanel işleyici çağrılmıyor.

  2. Özel bir kabarcıklama yönlendirilmiş olay olan CustomKey oluşturur ve CustomKey olayı için outerStackPanel işleyicisini 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, bastırılmış KeyDown yönlendirilmiş olayını outerStackPanel öğesine bağlı bir olay işleyicisini çalıştırmak için iki geçici çözüm gösterilmektedir.

  • PreviewKeyDown olay işleyicisini outerStackPanel öğesine ekleyin. 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.

  • Kod-behind'da KeyDown yöntemini kullanarak outerStackPanel öğesine, handledEventsToo parametresi true olarak ayarlanmış bir UIElement.AddHandler(RoutedEvent, Delegate, Boolean) olay işleyicisi ekleyin.

Uyarı

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 bakınız