Gambaran Umum Peristiwa Yang Dirutekan

Topik ini menjelaskan konsep peristiwa yang dirutekan di Windows Presentation Foundation (WPF). Topik ini mendefinisikan terminologi peristiwa yang dirutekan, menjelaskan bagaimana peristiwa yang dirutekan dirutekan melalui pohon elemen, meringkas cara Anda menangani peristiwa yang dirutekan, dan memperkenalkan cara membuat peristiwa rute kustom Anda sendiri.

Prasyarat

Topik ini mengasumsikan bahwa Anda memiliki pengetahuan dasar tentang runtime bahasa umum (CLR) dan pemrograman berorientasi objek, serta konsep bagaimana hubungan antara elemen WPF dapat dikonsep sebagai pohon. Untuk mengikuti contoh dalam topik ini, Anda juga harus memahami Extensible Application Markup Language (XAML) dan tahu cara menulis aplikasi atau halaman WPF yang sangat mendasar. Untuk informasi selengkapnya, lihat Panduan: Aplikasi desktop WPF pertama saya dan XAML di WPF.

Apa itu Peristiwa Yang Dirutekan?

Anda dapat memikirkan peristiwa yang dirutekan baik dari perspektif fungsional atau implementasi. Kedua definisi disajikan di sini, karena beberapa orang menemukan satu atau definisi lain lebih berguna.

Definisi fungsional: Peristiwa yang dirutekan adalah jenis peristiwa yang dapat memanggil penangan pada beberapa pendengar di pohon elemen, bukan hanya pada objek yang menaikkan peristiwa.

Definisi implementasi: Peristiwa yang dirutekan adalah peristiwa CLR yang didukung oleh instans RoutedEvent kelas dan diproses oleh sistem peristiwa Windows Presentation Foundation (WPF).

Aplikasi WPF yang khas berisi banyak elemen. Baik dibuat dalam kode atau dideklarasikan dalam XAML, elemen-elemen ini ada dalam hubungan pohon elemen satu sama lain. Rute peristiwa dapat melakukan perjalanan ke salah satu dari dua arah tergantung pada definisi peristiwa, tetapi umumnya rute berjalan dari elemen sumber dan kemudian "gelembung" ke atas melalui pohon elemen sampai mencapai akar pohon elemen (biasanya halaman atau jendela). Konsep gelembung ini mungkin sudah tidak asing bagi Anda jika Anda telah bekerja dengan model objek DHTML sebelumnya.

Pertimbangkan pohon elemen sederhana berikut:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

Pohon elemen ini menghasilkan sesuatu seperti berikut:

Yes, No, and Cancel buttons

Dalam pohon elemen yang disederhanakan ini, sumber Click peristiwa adalah salah Button satu elemen, dan mana pun yang Button diklik adalah elemen pertama yang memiliki kesempatan untuk menangani peristiwa. Tetapi jika tidak ada handler yang melekat Button pada tindakan pada peristiwa, maka peristiwa akan menggelegak ke atas ke Button induk di pohon elemen, yaitu StackPanel. Berpotensi, peristiwa gelembung ke Border, dan kemudian di luar ke akar halaman pohon elemen (tidak ditampilkan).

Dengan kata lain, rute peristiwa untuk peristiwa ini Click adalah:

Tombol-->StackPanel-->Border-->...

Skenario tingkat atas untuk Peristiwa Yang Dirutekan

Berikut ini adalah ringkasan singkat dari skenario yang memotivasi konsep peristiwa yang dirutekan, dan mengapa peristiwa CLR yang khas tidak memadai untuk skenario ini:

Komposisi kontrol dan enkapulasi: Berbagai kontrol dalam WPF memiliki con mode tenda l yang kaya. Misalnya, Anda dapat menempatkan gambar di dalam Button, yang secara efektif memperluas pohon visual tombol. Namun, gambar yang ditambahkan tidak boleh merusak perilaku pengujian hit yang menyebabkan tombol merespons Click kontennya, bahkan jika pengguna mengklik piksel yang secara teknis merupakan bagian dari gambar.

Titik lampiran handler tunggal: Dalam Formulir Windows, Anda harus melampirkan handler yang sama beberapa kali untuk memproses peristiwa yang dapat dimunculkan dari beberapa elemen. Peristiwa yang dirutekan memungkinkan Anda untuk melampirkan handler tersebut hanya sekali, seperti yang ditunjukkan pada contoh sebelumnya, dan menggunakan logika handler untuk menentukan dari mana peristiwa berasal jika perlu. Misalnya, ini mungkin handler untuk XAML yang ditampilkan sebelumnya:

private void CommonClickHandler(object sender, RoutedEventArgs e)
{
  FrameworkElement feSource = e.Source as FrameworkElement;
  switch (feSource.Name)
  {
    case "YesButton":
      // do something here ...
      break;
    case "NoButton":
      // do something ...
      break;
    case "CancelButton":
      // do something ...
      break;
  }
  e.Handled=true;
}
Private Sub CommonClickHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
  Dim feSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
  Select Case feSource.Name
    Case "YesButton"
      ' do something here ...
    Case "NoButton"
      ' do something ...
    Case "CancelButton"
      ' do something ...
  End Select
  e.Handled=True
End Sub

Penanganan kelas: Peristiwa yang dirutekan mengizinkan handler statis yang ditentukan oleh kelas. Handler kelas ini memiliki kesempatan untuk menangani peristiwa sebelum penangan instans terlampir dapat dilakukan.

Mereferensikan peristiwa tanpa refleksi: Teknik kode dan markup tertentu memerlukan cara untuk mengidentifikasi peristiwa tertentu. Peristiwa yang dirutekan membuat RoutedEvent bidang sebagai pengidentifikasi, yang menyediakan teknik identifikasi peristiwa yang kuat yang tidak memerlukan refleksi statis atau run-time.

Bagaimana Peristiwa Yang Dirutekan Diterapkan

Peristiwa yang dirutekan adalah peristiwa CLR yang didukung oleh instans RoutedEvent kelas dan terdaftar dengan sistem peristiwa WPF. Instans RoutedEvent yang diperoleh dari pendaftaran biasanya dipertahankan sebagai publicstaticreadonly anggota bidang kelas yang mendaftar dan dengan demikian "memiliki" peristiwa yang dirutekan. Koneksi ke peristiwa CLR bernama identik (yang kadang-kadang disebut peristiwa "pembungkus")) dicapai dengan mengesampingkan add implementasi dan remove untuk peristiwa CLR. Biasanya, dan remove dibiarkan add sebagai default implisit yang menggunakan sintaks peristiwa khusus bahasa yang sesuai untuk menambahkan dan menghapus handler peristiwa tersebut. Mekanisme dukungan peristiwa dan koneksi yang dirutekan secara konseptual mirip dengan bagaimana properti dependensi adalah properti CLR yang didukung oleh DependencyProperty kelas dan terdaftar dengan sistem properti WPF.

Contoh berikut menunjukkan deklarasi untuk peristiwa yang dirutekan kustom Tap , termasuk pendaftaran dan paparan RoutedEvent bidang pengidentifikasi dan add implementasi dan remove untuk Tap peristiwa CLR.

public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
    "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));

// Provide CLR accessors for the event
public event RoutedEventHandler Tap
{
        add { AddHandler(TapEvent, value); }
        remove { RemoveHandler(TapEvent, value); }
}
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))

' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
    AddHandler(ByVal value As RoutedEventHandler)
        Me.AddHandler(TapEvent, value)
    End AddHandler

    RemoveHandler(ByVal value As RoutedEventHandler)
        Me.RemoveHandler(TapEvent, value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.RaiseEvent(e)
    End RaiseEvent
End Event

Penanganan Aktivitas Yang Dirutekan dan XAML

Untuk menambahkan handler untuk peristiwa menggunakan XAML, Anda mendeklarasikan nama peristiwa sebagai atribut pada elemen yang merupakan pendengar peristiwa. Nilai atribut adalah nama metode handler yang Anda terapkan, yang harus ada di kelas parsial file code-behind.

<Button Click="b1SetColor">button</Button>

Sintaks XAML untuk menambahkan penanganan aktivitas CLR standar sama untuk menambahkan penanganan aktivitas yang dirutekan, karena Anda benar-benar menambahkan handler ke pembungkus peristiwa CLR, yang memiliki implementasi peristiwa yang dirutekan di bawahnya. Untuk informasi selengkapnya tentang menambahkan penanganan aktivitas di XAML, lihat XAML di WPF.

Strategi Perutean

Peristiwa yang dirutekan menggunakan salah satu dari tiga strategi perutean:

  • Gelembung: Penanganan aktivitas pada sumber peristiwa dipanggil. Peristiwa yang dirutekan kemudian merutekan ke elemen induk berturut-turut hingga mencapai akar pohon elemen. Sebagian besar peristiwa yang dirutekan menggunakan strategi perutean yang menggelegak. Peristiwa yang dirutekan gelembung umumnya digunakan untuk melaporkan perubahan input atau status dari kontrol yang berbeda atau elemen UI lainnya.

  • Langsung: Hanya elemen sumber itu sendiri yang diberi kesempatan untuk memanggil penangan sebagai respons. Ini dianalogikan dengan "perutean" yang Formulir Windows gunakan untuk peristiwa. Namun, tidak seperti peristiwa CLR standar, peristiwa yang dirutekan langsung mendukung penanganan kelas (penanganan kelas dijelaskan di bagian yang akan datang) dan dapat digunakan oleh EventSetter dan EventTrigger.

  • Tunneling: Awalnya, penanganan aktivitas di akar pohon elemen dipanggil. Peristiwa yang dirutekan kemudian melakukan perjalanan rute melalui elemen anak berturut-turut di sepanjang rute, menuju elemen node yang merupakan sumber peristiwa yang dirutekan (elemen yang mengangkat peristiwa yang dirutekan). Penerowongan peristiwa yang dirutekan sering digunakan atau ditangani sebagai bagian dari komposit untuk kontrol, sehingga peristiwa dari bagian komposit dapat sengaja ditekan atau digantikan oleh peristiwa yang khusus untuk kontrol lengkap. Peristiwa input yang disediakan dalam WPF sering kali diimplementasikan sebagai pasangan penerowongan/gelembung. Peristiwa penerowongan juga terkadang disebut sebagai peristiwa Pratinjau, karena konvensi penamaan yang digunakan untuk pasangan.

Mengapa Menggunakan Peristiwa Yang Dirutekan?

Sebagai pengembang aplikasi, Anda tidak selalu perlu mengetahui atau peduli bahwa peristiwa yang Anda tangani diimplementasikan sebagai peristiwa yang dirutekan. Peristiwa yang dirutekan memiliki perilaku khusus, tetapi perilaku tersebut sebagian besar tidak terlihat jika Anda menangani peristiwa pada elemen tempatnya dinaikkan.

Ketika peristiwa yang dirutekan menjadi kuat adalah jika Anda menggunakan salah satu skenario yang disarankan: menentukan handler umum pada akar umum, menyusun kontrol Anda sendiri, atau menentukan kelas kontrol kustom Anda sendiri.

Pendengar peristiwa yang dirutekan dan sumber peristiwa yang dirutekan tidak perlu berbagi peristiwa umum dalam hierarkinya. Apa pun UIElement atau ContentElement dapat menjadi pendengar peristiwa untuk setiap peristiwa yang dirutekan. Oleh karena itu, Anda dapat menggunakan serangkaian lengkap peristiwa rute yang tersedia di seluruh SET API kerja sebagai "antarmuka" konseptual di mana elemen yang berbeda dalam aplikasi dapat bertukar informasi peristiwa. Konsep "antarmuka" untuk peristiwa yang dirutekan ini terutama berlaku untuk peristiwa input.

Peristiwa yang dirutekan juga dapat digunakan untuk berkomunikasi melalui pohon elemen, karena data peristiwa untuk peristiwa diabadikan ke setiap elemen dalam rute. Satu elemen dapat mengubah sesuatu dalam data peristiwa, dan perubahan tersebut akan tersedia untuk elemen berikutnya dalam rute.

Selain aspek perutean, ada dua alasan lain bahwa setiap peristiwa WPF tertentu mungkin diimplementasikan sebagai peristiwa yang dirutekan alih-alih peristiwa CLR standar. Jika Anda menerapkan peristiwa Anda sendiri, Anda mungkin juga mempertimbangkan prinsip-prinsip ini:

  • Fitur gaya dan templat WPF tertentu seperti EventSetter dan EventTrigger mengharuskan peristiwa yang dirujuk menjadi peristiwa yang dirutekan. Ini adalah skenario pengidentifikasi peristiwa yang disebutkan sebelumnya.

  • Peristiwa yang dirutekan mendukung mekanisme penanganan kelas di mana kelas dapat menentukan metode statis yang memiliki kesempatan untuk menangani peristiwa yang dirutekan sebelum penangan instans terdaftar dapat mengaksesnya. Ini sangat berguna dalam desain kontrol, karena kelas Anda dapat memberlakukan perilaku kelas berbasis peristiwa yang tidak dapat ditekan secara tidak sengaja dengan menangani peristiwa pada instans.

Masing-masing pertimbangan di atas dibahas di bagian terpisah dari topik ini.

Menambahkan dan Menerapkan Penanganan Aktivitas untuk Peristiwa Yang Dirutekan

Untuk menambahkan penanganan aktivitas di XAML, Anda cukup menambahkan nama peristiwa ke elemen sebagai atribut dan menetapkan nilai atribut sebagai nama penanganan aktivitas yang mengimplementasikan delegasi yang sesuai, seperti dalam contoh berikut.

<Button Click="b1SetColor">button</Button>

b1SetColor adalah nama handler yang diimplementasikan yang berisi kode yang menangani Click peristiwa. b1SetColor harus memiliki tanda tangan RoutedEventHandler yang sama dengan delegasi, yang merupakan delegasi penanganan aktivitas untuk peristiwa tersebut Click . Parameter pertama dari semua delegasi penanganan aktivitas yang dirutekan menentukan elemen tempat penanganan aktivitas ditambahkan, dan parameter kedua menentukan data untuk peristiwa tersebut.

void b1SetColor(object sender, RoutedEventArgs args)
{
  //logic to handle the Click event
}
Private Sub b1SetColor(ByVal sender As Object, ByVal args As RoutedEventArgs)
  'logic to handle the Click event
End Sub

RoutedEventHandler adalah delegasi penanganan aktivitas dasar yang dirutekan. Untuk peristiwa yang dirutekan yang dikhususkan untuk kontrol atau skenario tertentu, delegasi yang akan digunakan untuk penanganan aktivitas yang dirutekan juga mungkin menjadi lebih khusus, sehingga dapat mengirimkan data peristiwa khusus. Misalnya, dalam skenario input umum, Anda dapat menangani peristiwa yang DragEnter dirutekan. Handler Anda harus mengimplementasikan DragEventHandler delegasi. Dengan menggunakan delegasi yang paling spesifik, Anda dapat memproses DragEventArgs di handler dan membaca Data properti , yang berisi payload clipboard dari operasi seret.

Untuk contoh lengkap cara menambahkan penanganan aktivitas ke elemen menggunakan XAML, lihat Menangani Peristiwa Yang Dirutekan.

Menambahkan handler untuk peristiwa yang dirutekan dalam aplikasi yang dibuat dalam kode sangat mudah. Penanganan aktivitas yang dirutekan selalu dapat ditambahkan melalui metode AddHandler pembantu (yang merupakan metode yang sama dengan panggilan backing yang ada untuk add.) Namun, peristiwa rute WPF yang ada umumnya memiliki implementasi add dukungan dan remove logika yang memungkinkan penangan untuk peristiwa yang dirutekan ditambahkan oleh sintaks peristiwa khusus bahasa, yang lebih intuitif daripada metode pembantu. Berikut ini adalah contoh penggunaan metode pembantu:

void MakeButton()
 {
     Button b2 = new Button();
     b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
 }
 void Onb2Click(object sender, RoutedEventArgs e)
 {
     //logic to handle the Click event
 }
Private Sub MakeButton()
     Dim b2 As New Button()
     b2.AddHandler(Button.ClickEvent, New RoutedEventHandler(AddressOf Onb2Click))
End Sub
 Private Sub Onb2Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
     'logic to handle the Click event     
 End Sub

Contoh berikutnya menunjukkan sintaks operator C# (Visual Basic memiliki sintaks operator yang sedikit berbeda karena penanganan dereferensinya):

void MakeButton2()
{
  Button b2 = new Button();
  b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
  //logic to handle the Click event
}
Private Sub MakeButton2()
  Dim b2 As New Button()
  AddHandler b2.Click, AddressOf Onb2Click2
End Sub
Private Sub Onb2Click2(ByVal sender As Object, ByVal e As RoutedEventArgs)
  'logic to handle the Click event     
End Sub

Untuk contoh cara menambahkan penanganan aktivitas dalam kode, lihat Menambahkan Penanganan Aktivitas Menggunakan Kode.

Jika Anda menggunakan Visual Basic, Anda juga dapat menggunakan Handles kata kunci untuk menambahkan handler sebagai bagian dari deklarasi handler. Untuk informasi selengkapnya, lihat Penanganan Peristiwa Visual Basic dan WPF.

Konsep Ditangani

Semua peristiwa yang dirutekan berbagi kelas dasar data peristiwa umum, RoutedEventArgs. RoutedEventArgsHandled menentukan properti , yang mengambil nilai Boolean. Tujuan properti Handled adalah untuk mengaktifkan penanganan aktivitas apa pun di sepanjang rute untuk menandai peristiwa yang dirutekan sebagai ditangani, dengan mengatur nilai Handled ke true. Setelah diproses oleh handler di satu elemen di sepanjang rute, data peristiwa bersama kembali dilaporkan ke setiap pendengar di sepanjang rute.

Nilai Handled memengaruhi bagaimana peristiwa yang dirutekan dilaporkan atau diproses saat berjalan lebih jauh di sepanjang rute. Jika Handled berada true dalam data peristiwa untuk peristiwa yang dirutekan, maka handler yang mendengarkan peristiwa yang dirutekan pada elemen lain umumnya tidak lagi dipanggil untuk instans peristiwa tertentu tersebut. Ini benar baik untuk handler yang dilampirkan di XAML dan untuk handler yang ditambahkan oleh sintaks lampiran penanganan aktivitas khusus bahasa seperti += atau Handles. Untuk skenario handler yang paling umum, menandai peristiwa seperti yang ditangani dengan mengatur Handled untuk true akan "menghentikan" perutean untuk rute penerowongan atau rute yang menggelegak, dan juga untuk peristiwa apa pun yang ditangani pada titik dalam rute oleh penangan kelas.

Namun, ada mekanisme "handledEventsToo" di mana pendengar masih dapat menjalankan handler sebagai respons terhadap peristiwa yang dirutekan di mana Handled berada true dalam data peristiwa. Dengan kata lain, rute peristiwa tidak benar-benar dihentikan dengan menandai data peristiwa sebagai ditangani. Anda hanya dapat menggunakan mekanisme handledEventsToo dalam kode, atau dalam :EventSetter

Selain perilaku yang Handled dihasilkan status dalam peristiwa yang dirutekan, konsep Handled memiliki implikasi tentang bagaimana Anda harus merancang aplikasi Anda dan menulis kode penanganan aktivitas. Anda dapat mengkonsep Handled sebagai protokol sederhana yang diekspos oleh peristiwa yang dirutekan. Persis bagaimana Anda menggunakan protokol ini terserah Anda, tetapi desain konseptual untuk bagaimana nilai Handled yang dimaksudkan untuk digunakan adalah sebagai berikut:

  • Jika peristiwa yang dirutekan ditandai sebagai ditangani, maka peristiwa tersebut tidak perlu ditangani lagi oleh elemen lain di sepanjang rute tersebut.

  • Jika peristiwa yang dirutekan tidak ditandai sebagai ditangani, maka listener lain yang sebelumnya berada di sepanjang rute telah memilih untuk tidak mendaftarkan handler, atau handler yang terdaftar memilih untuk tidak memanipulasi data peristiwa dan mengatur Handled ke true. (Atau, tentu saja mungkin bahwa pendengar saat ini adalah titik pertama dalam rute.) Handler pada listener saat ini sekarang memiliki tiga kemungkinan kursus tindakan:

    • Tidak mengambil tindakan apa-apa; peristiwa tetap tidak tertangani, dan peristiwa merutekan ke pendengar berikutnya.

    • Jalankan kode sebagai respons terhadap peristiwa, tetapi buat penentuan bahwa tindakan yang diambil tidak cukup substansial untuk menjamin menandai peristiwa seperti yang ditangani. Peristiwa dirutekan ke pendengar berikutnya.

    • Jalankan kode sebagai respons terhadap peristiwa. Tandai peristiwa sebagai ditangani dalam data peristiwa yang diteruskan ke handler, karena tindakan yang diambil dianggap cukup substansial untuk menjamin penandaan sebagai ditangani. Acara ini masih merutekan ke pendengar berikutnya, tetapi dengan Handled=true dalam data peristiwanya, sehingga hanya handledEventsToo pendengar yang memiliki kesempatan untuk memanggil handler lebih lanjut.

Desain konseptual ini diperkuat oleh perilaku perutean yang disebutkan sebelumnya: lebih sulit (meskipun masih mungkin dalam kode atau gaya) untuk melampirkan handler untuk peristiwa rute yang dipanggil bahkan jika handler sebelumnya di sepanjang rute telah diatur Handled ke true.

Untuk informasi selengkapnya tentang Handled, penanganan kelas peristiwa yang dirutekan, dan rekomendasi tentang kapan tepat untuk menandai peristiwa yang dirutekan sebagai Handled, lihat Menandai Peristiwa Rute sebagai Ditangani, dan Penanganan Kelas.

Dalam aplikasi, cukup umum untuk hanya menangani peristiwa yang dirutekan yang menggelegak pada objek yang menaikkannya, dan tidak peduli dengan karakteristik perutean peristiwa sama sekali. Namun, ini masih merupakan praktik yang baik untuk menandai peristiwa yang dirutekan seperti yang ditangani dalam data peristiwa, untuk mencegah efek samping yang tidak terduga untuk berjaga-jaga jika elemen yang lebih jauh dari pohon elemen juga memiliki handler yang terpasang untuk peristiwa yang dirutekan yang sama.

Penangan Kelas

Jika Anda mendefinisikan kelas yang berasal dari DependencyObject, Anda juga dapat menentukan dan melampirkan handler kelas untuk peristiwa yang dirutekan yang merupakan anggota peristiwa yang dideklarasikan atau diwariskan dari kelas Anda. Handler kelas dipanggil sebelum penanganan pendengar instans yang dilampirkan ke instans kelas tersebut, setiap kali peristiwa yang dirutekan mencapai instans elemen dalam rutenya.

Beberapa kontrol WPF memiliki penanganan kelas yang melekat untuk peristiwa tertentu yang dirutekan. Ini mungkin memberikan penampilan keluar bahwa peristiwa yang dirutekan tidak pernah muncul, tetapi pada kenyataannya sedang ditangani kelas, dan peristiwa yang dirutekan berpotensi masih dapat ditangani oleh handler instans Anda jika Anda menggunakan teknik tertentu. Selain itu, banyak kelas dan kontrol dasar mengekspos metode virtual yang dapat digunakan untuk mengambil alih perilaku penanganan kelas. Untuk informasi selengkapnya tentang cara mengatasi penanganan kelas yang tidak diinginkan dan menentukan penanganan kelas Anda sendiri di kelas kustom, lihat Menandai Peristiwa Yang Dirutekan sebagai Ditangani, dan Penanganan Kelas.

Kejadian Terlampir di WPF

Bahasa XAML juga mendefinisikan jenis peristiwa khusus yang disebut peristiwa terlampir. Kejadian terlampir memungkinkan Anda menambahkan handler untuk peristiwa tertentu ke elemen arbitrer. Elemen yang menangani peristiwa tidak perlu menentukan atau mewarisi peristiwa terlampir, dan tidak ada objek yang berpotensi meningkatkan peristiwa atau instans penanganan tujuan harus menentukan atau "memiliki" peristiwa tersebut sebagai anggota kelas.

Sistem input WPF menggunakan peristiwa terlampir secara ekstensif. Namun, hampir semua peristiwa terlampir ini diteruskan melalui elemen dasar. Peristiwa input kemudian muncul sebagai peristiwa rute yang tidak terpasang yang setara yang merupakan anggota kelas elemen dasar. Misalnya, peristiwa Mouse.MouseDown terlampir yang mendasar dapat lebih mudah ditangani pada apa pun yang UIElement diberikan UIElement dengan menggunakannya MouseDown daripada berurusan dengan sintaks peristiwa terlampir baik di XAML atau kode.

Untuk informasi selengkapnya tentang peristiwa terlampir di WPF, lihat Gambaran Umum Peristiwa Terlampir.

Nama Peristiwa yang Memenuhi Syarat di XAML

Penggunaan sintaksis lain yang menyerupan typename.sintaks peristiwa terlampir nama peristiwa tetapi tidak secara ketat berbicara penggunaan peristiwa terlampir adalah ketika Anda melampirkan handler untuk peristiwa rute yang dinaikkan oleh elemen turunan. Anda melampirkan handler ke induk umum, untuk memanfaatkan perutean peristiwa, meskipun induk umum mungkin tidak memiliki peristiwa yang dirutekan yang relevan sebagai anggota. Pertimbangkan contoh ini lagi:

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

Di sini, pendengar elemen induk tempat handler ditambahkan adalah StackPanel. Namun, ini menambahkan handler untuk peristiwa rute yang dideklarasikan dan akan dinaikkan oleh Button kelas (ButtonBase sebenarnya, tetapi tersedia untuk Button melalui warisan). Button "memiliki" peristiwa, tetapi sistem peristiwa yang dirutekan mengizinkan handler untuk setiap peristiwa yang dirutekan untuk dilampirkan ke pendengar apa pun UIElement atau ContentElement instans yang dapat melampirkan pendengar untuk peristiwa runtime bahasa umum (CLR). Namespace xmlns default untuk nama atribut peristiwa yang memenuhi syarat ini biasanya merupakan namespace xmlns WPF default, tetapi Anda juga dapat menentukan namespace awalan untuk peristiwa rute kustom. Untuk informasi selengkapnya tentang xmln, lihat Namespace Layanan XAML dan Pemetaan Namespace layanan untuk WPF XAML.

Peristiwa Input WPF

Salah satu aplikasi sering peristiwa yang dirutekan dalam platform WPF adalah untuk peristiwa input. Di WPF, penerowongan nama peristiwa yang dirutekan diawali dengan kata "Pratinjau" menurut konvensi. Peristiwa input sering datang berpasangan, dengan satu menjadi peristiwa gelembung dan yang lain menjadi peristiwa penerowongan. Misalnya, KeyDown peristiwa dan PreviewKeyDown peristiwa memiliki tanda tangan yang sama, dengan yang sebelumnya menjadi peristiwa input yang menggelegak dan yang terakhir adalah peristiwa input penerowongan. Terkadang, peristiwa input hanya memiliki versi gelembung, atau mungkin hanya versi yang dirutekan langsung. Dalam dokumentasi, topik peristiwa yang dirutekan merujuk silang peristiwa rute serupa dengan strategi perutean alternatif jika peristiwa rute tersebut ada, dan bagian di halaman referensi terkelola mengklarifikasi strategi perutean setiap peristiwa yang dirutekan.

Peristiwa input WPF yang datang berpasangan diimplementasikan sehingga satu tindakan pengguna dari input, seperti penekanan tombol mouse, akan meningkatkan kedua peristiwa pasangan yang dirutekan secara berurutan. Pertama, peristiwa penerowongan dinaikkan dan menempuh rutenya. Kemudian peristiwa menggelegak dinaikkan dan menempuh rutenya. Dua peristiwa tersebut secara harfiah berbagi instans data peristiwa yang sama, karena RaiseEvent panggilan metode di kelas penerapan yang memunculkan peristiwa menggelegak mendengarkan data peristiwa dari peristiwa penerowongan dan menggunakannya kembali dalam peristiwa baru yang dimunculkan. Pendengar dengan handler untuk peristiwa penerowongan memiliki kesempatan pertama untuk menandai peristiwa yang dirutekan yang ditangani (penangan kelas terlebih dahulu, lalu penangan instans). Jika elemen di sepanjang rute penerowongan menandai peristiwa yang dirutekan seperti yang ditangani, data peristiwa yang sudah ditangani dikirim untuk peristiwa gelembung, dan handler umum yang dilampirkan untuk peristiwa input gelembung yang setara tidak akan dipanggil. Untuk penampilan keluar itu akan seolah-olah peristiwa gelembung yang ditangani bahkan belum dinaikkan. Perilaku penanganan ini berguna untuk komposit kontrol, di mana Anda mungkin ingin semua peristiwa input berbasis uji hit atau peristiwa input berbasis fokus dilaporkan oleh kontrol akhir Anda, bukan bagian kompositnya. Elemen kontrol akhir lebih dekat ke akar dalam pembuatan, dan oleh karena itu memiliki kesempatan untuk kelas menangani peristiwa penerowongan terlebih dahulu dan mungkin untuk "mengganti" peristiwa yang dirutekan dengan peristiwa yang lebih spesifik kontrol, sebagai bagian dari kode yang mendukung kelas kontrol.

Sebagai ilustrasi tentang cara kerja pemrosesan peristiwa input, pertimbangkan contoh peristiwa input berikut. Dalam ilustrasi pohon berikut, leaf element #2 adalah sumber dari peristiwa PreviewMouseDown dan kemudian MouseDown :

Event routing diagram

Urutan pemrosesan peristiwa adalah sebagai berikut:

  1. PreviewMouseDown (terowongan) pada elemen root.

  2. PreviewMouseDown (tunnel) pada elemen perantara #1.

  3. PreviewMouseDown (tunnel) pada elemen sumber #2.

  4. MouseDown (gelembung) pada elemen sumber #2.

  5. MouseDown (gelembung) pada elemen menengah #1.

  6. MouseDown (gelembung) pada elemen akar.

Delegasi penanganan aktivitas yang dirutekan menyediakan referensi ke dua objek: objek yang menaikkan peristiwa dan objek tempat handler dipanggil. Objek tempat handler dipanggil adalah objek yang dilaporkan oleh sender parameter . Objek tempat peristiwa pertama kali dinaikkan dilaporkan oleh Source properti dalam data peristiwa. Peristiwa yang dirutekan masih dapat dinaikkan dan ditangani oleh objek yang sama, dalam hal sender ini dan Source identik (ini adalah kasus dengan Langkah 3 dan 4 dalam daftar contoh pemrosesan peristiwa).

Karena penerowongan dan gelembung, elemen induk menerima peristiwa input di mana Source adalah salah satu elemen anak mereka. Ketika penting untuk mengetahui apa elemen sumbernya, Anda dapat mengidentifikasi elemen sumber dengan mengakses Source properti .

Biasanya, setelah peristiwa input ditandai Handled, handler lebih lanjut tidak dipanggil. Biasanya, Anda harus menandai peristiwa input sebagai ditangani segera setelah handler dipanggil yang membahas penanganan logis khusus aplikasi Anda dari arti peristiwa input.

Pengecualian untuk pernyataan umum tentang Handled status ini adalah bahwa penangan peristiwa input yang terdaftar untuk dengan sengaja mengabaikan Handled status data peristiwa masih akan dipanggil di sepanjang salah satu rute. Untuk informasi selengkapnya, lihat Pratinjau Peristiwa atau Menandai Peristiwa Rute sebagai Ditangani, dan Penanganan Kelas.

Model data peristiwa bersama antara peristiwa penerowongan dan gelembung, dan peningkatan berurutan penerowongan pertama kemudian menggelegak peristiwa, bukan konsep yang umumnya berlaku untuk semua peristiwa yang dirutekan. Perilaku tersebut secara khusus diimplementasikan oleh bagaimana perangkat input WPF memilih untuk menaikkan dan menghubungkan pasangan peristiwa input. Menerapkan peristiwa input Anda sendiri adalah skenario lanjutan, tetapi Anda mungkin memilih untuk mengikuti model tersebut untuk peristiwa input Anda sendiri juga.

Kelas tertentu memilih untuk menangani kelas peristiwa input tertentu, biasanya dengan maksud untuk mendefinisikan ulang arti peristiwa input berbasis pengguna tertentu dalam kontrol tersebut dan meningkatkan peristiwa baru. Untuk informasi selengkapnya, lihat Menandai Peristiwa Yang Dirutekan sebagai Ditangani, dan Penanganan Kelas.

Untuk informasi selengkapnya tentang input dan bagaimana input dan peristiwa berinteraksi dalam skenario aplikasi umum, lihat Gambaran Umum Input.

EventSetters dan EventTriggers

Dalam gaya, Anda dapat menyertakan beberapa sintaks penanganan peristiwa XAML yang telah dideklarasikan sebelumnya dalam markup dengan menggunakan EventSetter. Saat gaya diterapkan, handler yang dirujuk ditambahkan ke instans bergaya. Anda dapat mendeklarasikan satu-satunya EventSetter untuk peristiwa yang dirutekan. Berikut adalah contohnya. Perhatikan bahwa metode yang dirujuk b1SetColor di sini ada dalam file code-behind.

<StackPanel
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.EventOvw2"
  Name="dpanel2"
  Initialized="PrimeHandledToo"
>
  <StackPanel.Resources>
    <Style TargetType="{x:Type Button}">
      <EventSetter Event="Click" Handler="b1SetColor"/>
    </Style>
  </StackPanel.Resources>
  <Button>Click me</Button>
  <Button Name="ThisButton" Click="HandleThis">
    Raise event, handle it, use handled=true handler to get it anyway.
  </Button>
</StackPanel>

Keuntungan yang diperoleh di sini adalah bahwa gaya kemungkinan berisi banyak informasi lain yang dapat berlaku untuk tombol apa pun di aplikasi Anda, dan memiliki bagian dari gaya itu EventSetter mempromosikan penggunaan kembali kode bahkan pada tingkat markup. Selain itu, EventSetter abstrak nama metode untuk handler selangkah lebih jauh dari aplikasi umum dan markup halaman.

Sintaksis khusus lainnya yang menggabungkan fitur peristiwa dan animasi WPF yang dirutekan adalah EventTrigger. EventSetterSeperti halnya , hanya peristiwa yang dirutekan yang dapat digunakan untuk EventTrigger. Biasanya, EventTrigger dideklarasikan sebagai bagian dari gaya, tetapi EventTrigger juga dapat dideklarasikan pada elemen tingkat halaman sebagai bagian Triggers dari koleksi, atau dalam ControlTemplate. Memungkinkan EventTrigger Anda menentukan Storyboard yang berjalan setiap kali peristiwa yang dirutekan mencapai elemen dalam rutenya yang mendeklarasikan EventTrigger untuk peristiwa tersebut. Keuntungan dari EventTrigger lebih hanya menangani peristiwa dan menyebabkannya memulai papan cerita yang ada adalah bahwa memberikan kontrol yang EventTrigger lebih baik atas papan cerita dan perilaku run-time-nya. Untuk informasi selengkapnya, lihat Menggunakan Pemicu Peristiwa untuk Mengontrol Papan Cerita Setelah Dimulai.

Selengkapnya Tentang Peristiwa Yang Dirutekan

Topik ini terutama membahas peristiwa yang dirutekan dari perspektif menggambarkan konsep dasar dan menawarkan panduan tentang bagaimana dan kapan harus menanggapi peristiwa yang dirutekan yang sudah ada di berbagai elemen dan kontrol dasar. Namun, Anda dapat membuat peristiwa yang dirutekan sendiri di kelas kustom Anda bersama dengan semua dukungan yang diperlukan, seperti kelas dan delegasi data peristiwa khusus. Pemilik peristiwa yang dirutekan dapat menjadi kelas apa pun, tetapi peristiwa yang dirutekan harus dinaikkan oleh dan ditangani oleh UIElement atau ContentElement turunan kelas agar berguna. Untuk informasi selengkapnya tentang peristiwa kustom, lihat Membuat Peristiwa Rute Kustom.

Baca juga