Pratinjau peristiwa (WPF .NET)
Peristiwa pratinjau, juga dikenal sebagai peristiwa penerowongan, adalah peristiwa yang dirutekan yang melintasi ke bawah melalui pohon elemen dari elemen akar aplikasi ke elemen yang menaikkan peristiwa. Elemen yang menaikkan peristiwa dilaporkan sebagai Source dalam data peristiwa. Tidak semua skenario peristiwa mendukung atau memerlukan peristiwa pratinjau. Artikel ini menjelaskan di mana peristiwa pratinjau ada dan bagaimana aplikasi atau komponen dapat berinteraksi dengannya. Untuk informasi tentang cara membuat peristiwa pratinjau, lihat Cara membuat peristiwa rute kustom.
Prasyarat
Artikel ini mengasumsikan pengetahuan dasar tentang peristiwa yang dirutekan, dan anda telah membaca ringkasan peristiwa yang dirutekan. Untuk mengikuti contoh dalam artikel ini, ini membantu jika Anda terbiasa dengan Extensible Application Markup Language (XAML) dan tahu cara menulis aplikasi Windows Presentation Foundation (WPF).
Pratinjau peristiwa yang ditandai sebagai ditangani
Berhati-hatilah saat menandai peristiwa pratinjau sebagai ditangani dalam data peristiwa. Menandai peristiwa pratinjau seperti yang ditangani pada elemen selain elemen yang menaikkannya dapat mencegah elemen yang menaikkannya menangani peristiwa. Terkadang menandai peristiwa pratinjau seperti yang ditangani disengaja. Misalnya, kontrol komposit mungkin menekan peristiwa yang diangkat oleh komponen individual dan menggantinya dengan peristiwa yang dinaikkan oleh kontrol lengkap. Peristiwa kustom untuk kontrol dapat menyediakan data peristiwa yang disesuaikan dan pemicu berdasarkan hubungan status komponen.
Untuk peristiwa input, data peristiwa dibagikan oleh pratinjau dan non-pratinjau (gelembung) yang setara dengan setiap peristiwa. Jika Anda menggunakan penanganan kelas peristiwa pratinjau untuk menandai peristiwa input sebagai ditangani, penanganan kelas untuk peristiwa input gelembung biasanya tidak akan dipanggil. Atau, jika Anda menggunakan penanganan instans peristiwa pratinjau untuk menandai peristiwa sebagai ditangani, penanganan instans untuk peristiwa input gelembung biasanya tidak akan dipanggil. Meskipun Anda dapat mengonfigurasi penangan kelas dan instans untuk dipanggil bahkan jika peristiwa ditandai sebagai ditangani, konfigurasi handler tersebut tidak umum. Untuk informasi selengkapnya tentang penanganan kelas dan hubungannya dengan peristiwa pratinjau, lihat Menandai peristiwa yang dirutekan sebagai penanganan dan penanganan kelas.
Catatan
Tidak semua peristiwa pratinjau adalah peristiwa penerowongan . Misalnya, PreviewMouseLeftButtonDown peristiwa input mengikuti rute ke bawah melalui pohon elemen, tetapi merupakan peristiwa rute langsung yang dinaikkan dan disalurkan kembali oleh masing-masing UIElement dalam rute.
Bekerja di sekitar penekanan peristiwa berdasarkan kontrol
Beberapa kontrol komposit menekan peristiwa input di tingkat komponen untuk menggantinya dengan peristiwa tingkat tinggi yang disesuaikan. Misalnya, WPF ButtonBase menandai MouseLeftButtonDown peristiwa input gelembung seperti yang ditangani dalam metodenya OnMouseLeftButtonDown dan menaikkan Click peristiwa. Peristiwa MouseLeftButtonDown
dan data peristiwanya masih berlanjut di sepanjang rute pohon elemen, tetapi karena peristiwa ditandai sebagai Handled dalam data peristiwa, hanya penangan yang dikonfigurasi untuk merespons peristiwa yang ditangani yang dipanggil.
Jika Anda ingin elemen lain menuju akar aplikasi Anda menangani peristiwa rute yang ditandai sebagai ditangani, Anda dapat:
Lampirkan handler dengan memanggil UIElement.AddHandler(RoutedEvent, Delegate, Boolean) metode dan mengatur parameter
handledEventsToo
ketrue
. Pendekatan ini mengharuskan melampirkan penanganan aktivitas di code-behind, setelah mendapatkan referensi objek ke elemen yang akan dilampirkan.Jika peristiwa yang ditandai sebagai ditangani adalah peristiwa gelembung, lampirkan handler untuk peristiwa pratinjau yang setara jika tersedia. Misalnya, jika kontrol menekan MouseLeftButtonDown peristiwa, Anda dapat melampirkan handler untuk peristiwa sebagai gantinya PreviewMouseLeftButtonDown . Pendekatan ini hanya berfungsi untuk peristiwa input elemen dasar yang mengimplementasikan strategi perutean penerowongan dan bubbling dan berbagi data peristiwa.
Contoh berikut mengimplementasikan kontrol kustom dasar bernama componentWrapper
yang berisi TextBox. Kontrol ditambahkan ke bernama 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>
Kontrol componentWrapper
mendengarkan peristiwa gelembung yang KeyDown diangkat oleh komponennya TextBox
setiap kali penekanan tombol terjadi. Pada kejadian tersebut componentWrapper
, kontrol:
KeyDown
Menandai peristiwa bergelombang yang dirutekan sebagai ditangani untuk menekannya. Akibatnya, hanyaouterStackPanel
handler yang dikonfigurasi di code-behind untuk merespons peristiwa yang ditanganiKeyDown
yang dipicu. HandlerouterStackPanel
yang dilampirkan di XAML untukKeyDown
peristiwa tidak dipanggil.Menaikkan peristiwa rute gelembung kustom bernama
CustomKey
, yang memicuouterStackPanel
handler untuk peristiwa tersebutCustomKey
.
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
Contoh menunjukkan dua solusi untuk mendapatkan peristiwa rute yang ditekan KeyDown
untuk memanggil penanganan aktivitas yang dilampirkan ke outerStackPanel
:
Lampirkan PreviewKeyDown penanganan aktivitas ke
outerStackPanel
. Karena peristiwa yang dirutekan input pratinjau mendahului peristiwa yang dirutekan gelembung yang setara,PreviewKeyDown
handler dalam contoh berjalan di depanKeyDown
handler yang menekan pratinjau dan peristiwa gelembung melalui data peristiwa bersama mereka.KeyDown
Lampirkan penanganan aktivitas keouterStackPanel
dengan menggunakan UIElement.AddHandler(RoutedEvent, Delegate, Boolean) metode di code-behind, dengan parameter diaturhandledEventsToo
ketrue
.
Catatan
Menandai pratinjau atau non-pratinjau yang setara dengan peristiwa input seperti yang ditangani adalah strategi untuk menekan peristiwa yang dimunculkan oleh komponen kontrol. Pendekatan yang Anda gunakan tergantung pada persyaratan aplikasi Anda.
Lihat juga
.NET Desktop feedback