Yönlendirilen olayları işlenmiş olarak işaretleme ve sınıf işleme (WPF .NET)
Yönlendirilmiş bir olayı işlenmiş olarak işaretlemek için mutlak bir kural olmasa da, kodunuz olaya önemli bir şekilde yanıt veriyorsa bir olayı işlenmiş olarak işaretlemeyi göz önünde bulundurun. İşlendi olarak işaretlenen yönlendirilmiş bir olay, yolu boyunca devam eder, ancak yalnızca işlenen olaylara yanıt verecek şekilde yapılandırılmış işleyiciler çağrılır. Temel olarak, yönlendirilen bir olayı işlenmiş olarak işaretlemek, görünürlüğünü olay yolu boyunca dinleyicilere sınırlar.
Yönlendirilen olay işleyicileri örnek işleyicileri veya sınıf işleyicileri olabilir. Örnek işleyicileri, nesneler veya XAML öğelerinde yönlendirilen olayları işler. Sınıf işleyicileri, sınıf düzeyinde yönlendirilmiş bir olayı işler ve sınıfın herhangi bir örneğinde aynı olaya yanıt veren herhangi bir örnek işleyicisi çağrılır. Yönlendirilen olaylar işlendi olarak işaretlendiğinde, bunlar genellikle sınıf işleyicileri içinde bu şekilde işaretlenir. Bu makalede, yönlendirilen olayları işlenmek üzere işaretlemenin avantajları ve olası tuzakları, farklı türlerdeki yönlendirilmiş olaylar ve yönlendirilen olay işleyicileri ve bileşik denetimlerde olay gizleme işlemleri ele alınmaktadır.
Ö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.
Yönlendirilen olaylar ne zaman işlenmiş olarak işaretlenmeli?
Genellikle, yönlendirilen her olay için yalnızca bir işleyici önemli bir yanıt sağlamalıdır. Birden çok işleyici arasında önemli bir yanıt sağlamak için yönlendirilmiş olay sistemini kullanmaktan kaçının. Önemli bir yanıtı oluşturan şeyin tanımı özneldir ve uygulamanıza bağlıdır. Genel rehberlik olarak:
- Önemli yanıtlar arasında odağı ayarlama, genel durumu değiştirme, görsel gösterimi etkileyen özellikleri ayarlama, yeni olaylar oluşturma ve bir olayı tamamen işleme sayılabilir.
- Önemsiz yanıtlar, görsel veya programlı etki olmadan özel durumu değiştirmeyi, olay günlüğünü ve olaya yanıt vermeden olay verilerini incelemeyi içerir.
Bazı WPF denetimleri, işlenmiş olarak işaretleyerek daha fazla işleme gerektirmeyen bileşen düzeyinde olayları gizler. Bir denetim tarafından işlendi olarak işaretlenmiş bir olayı işlemek istiyorsanız bkz . Denetimler tarafından olay gizlemeye geçici bir çözüm.
Bir olayı işlenmiş olarak işaretlemek için, olay verilerindeki özellik değerini olarak true
ayarlayınHandled. Bu değeri false
değerine geri döndürmek mümkün olsa da, bunu yapmak nadir olmalıdır.
Yönlendirilen olay çiftlerini önizleme ve kabarcık oluşturma
Yönlendirilen olay çiftlerinin önizlemesi ve kabarcıkları giriş olaylarına özeldir. Çeşitli giriş olayları, ve gibi bir tünel oluşturma ve yönlendirilmiş olay çifti kabarcıkları PreviewKeyDown uygular.KeyDown Ön ek, Preview
önizleme olayı tamamlandıktan sonra kabarcıklanma olayının başlatıldığını belirtir. Her önizleme ve kabarcık oluşturma olay çifti, olay verilerinin aynı örneğini paylaşır.
Yönlendirilen olay işleyicileri, bir olayın yönlendirme stratejisine karşılık gelen bir sırayla çağrılır:
- Önizleme olayı, uygulama kök öğesinden yönlendirilen olayı tetikleyen öğeye doğru ilerler. Uygulama kök öğesine eklenen önizleme olay işleyicileri önce çağrılır, ardından ardışık iç içe geçmiş öğelere eklenmiş işleyiciler kullanılır.
- Önizleme olayı tamamlandıktan sonra eşleştirilmiş kabarcıklama olayı, yönlendirilen olayı uygulama kök öğesine yükselten öğeden hareket eder. Yönlendirilen olayı tetikleyen aynı öğeye bağlı olan kabarcık olay işleyicileri önce çağrılır, ardından ardışık üst öğelere eklenmiş işleyiciler.
Eşleştirilmiş önizleme ve kabarcıklama olayları, kendi yönlendirilmiş olaylarını bildiren ve oluşturan çeşitli WPF sınıflarının iç uygulamasının bir parçasıdır. Bu sınıf düzeyinde iç uygulama olmadan, yönlendirilen olayların önizlemesi ve kabarcıkları tamamen ayrıdır ve olay adlandırmadan bağımsız olarak olay verilerini paylaşmaz. Özel bir sınıfta kabarcıklama veya tünel oluşturma giriş yönlendirilmiş olayları uygulama hakkında bilgi için bkz . Özel yönlendirilmiş olay oluşturma.
Her önizleme ve kabarcıklama olay çifti olay verilerinin aynı örneğini paylaştığından, önizlemeye yönlendirilen bir olay işlendi olarak işaretlenirse eşleştirilmiş kabarcıklama olayı da işlenir. Kabarcıklı yönlendirilmiş bir olay işlendi olarak işaretlenirse, önizleme olayı tamamlandığından eşleştirilmiş önizleme olayını etkilemez. Önizlemeyi işaretlerken ve giriş olay çiftlerini işlenirken dikkatli olun. İşlenen bir önizleme giriş olayı tünel yolunun geri kalanı için normal olarak kaydedilmiş olay işleyicilerini çağırmaz ve eşleştirilmiş kabarcıklama olayı tetiklenmez. İşlenen bir kabarcık giriş olayı, kabarcık oluşturma yolunun geri kalanı için normal olarak kaydedilmiş olay işleyicileri çağırmaz.
Örnek ve sınıf tarafından yönlendirilen olay işleyicileri
Yönlendirilen olay işleyicileri örnek işleyicileri veya sınıf işleyicileri olabilir. Belirli bir sınıf için sınıf işleyicileri, bu sınıfın herhangi bir örneğinde aynı olaya yanıt veren herhangi bir örnek işleyiciden önce çağrılır. Bu davranış nedeniyle, yönlendirilen olaylar işlendi olarak işaretlendiğinde genellikle sınıf işleyicileri içinde bu şekilde işaretlenir. İki tür sınıf işleyicisi vardır:
- Statik sınıf oluşturucusunun RegisterClassHandler içinde yöntemini çağırarak kaydedilen statik sınıf olay işleyicileri.
- Temel sınıf sanal olay yöntemleri geçersiz kılınarak kaydedilen sınıf olay işleyicilerini geçersiz kılın. Temel sınıf sanal olay yöntemleri öncelikli olarak giriş olayları için vardır ve On<olay adı ve OnPreview<olay adı>> ile başlayan adlara sahiptir.
Örnek olay işleyicileri
Doğrudan yöntemini çağırarak nesnelere veya XAML öğelerine AddHandler örnek işleyicileri ekleyebilirsiniz. WPF yönlendirilmiş olaylar, olay işleyicileri eklemek için yöntemini kullanan AddHandler
ortak dil çalışma zamanı (CLR) olay sarmalayıcısını uygular. Olay işleyicileri eklemeye yönelik XAML özniteliği söz dizimi CLR olay sarmalayıcısına çağrıyla sonuçlandığından, XAML'de işleyicilerin eklenmesi bile bir AddHandler
çağrıya çözümleniyor. İşlenen olaylar için:
- XAML öznitelik söz dizimi veya ortak imzası
AddHandler
kullanılarak eklenen işleyiciler çağrılmıyor. - parametresi ayarlanmış
true
aşırı yüklemehandledEventsToo
kullanılarak AddHandler(RoutedEvent, Delegate, Boolean) eklenen işleyiciler çağrılır. İşlenen olaylara yanıt vermek gerektiğinde bu aşırı yükleme nadir durumlarda kullanılabilir. Örneğin, öğe ağacındaki bazı öğeler bir olayı işlendi olarak işaretlemiştir, ancak olay yolu boyunca daha ileriki diğer öğelerin işlenen olaya yanıt vermesi gerekir.
Aşağıdaki XAML örneği, adlı bir öğesini adlandırılmış componentWrapper
bir öğesine sarmalayan TextBox componentTextBox
adlı outerStackPanel
özel bir StackPanel denetim ekler. Olay için PreviewKeyDown bir örnek olay işleyicisi, using XAML özniteliği söz dizimine eklenir componentWrapper
. Sonuç olarak, örnek işleyicisi yalnızca tarafından componentTextBox
tetiklenen işlenmeyen PreviewKeyDown
tünel olaylarına yanıt verir.
<StackPanel Name="outerStackPanel" VerticalAlignment="Center">
<custom:ComponentWrapper
x:Name="componentWrapper"
TextBox.PreviewKeyDown="HandlerInstanceEventInfo"
HorizontalAlignment="Center">
<TextBox Name="componentTextBox" Width="200" />
</custom:ComponentWrapper>
</StackPanel>
MainWindow
Oluşturucu, parametresi olarak ayarlanmış şekilde aşırı yükleme handledEventsToo
kullanarak UIElement.AddHandler(RoutedEvent, Delegate, Boolean) öğesine kabarcıklama olayı componentWrapper
için KeyDown
bir örnek işleyicisi true
ekler. Sonuç olarak, örnek olay işleyicisi hem işlenmeyen hem de işlenen olaylara yanıt verir.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Attach an instance handler on componentWrapper that will be invoked by handled KeyDown events.
componentWrapper.AddHandler(KeyDownEvent, new RoutedEventHandler(Handler.InstanceEventInfo),
handledEventsToo: true);
}
// The handler attached to componentWrapper in XAML.
public void HandlerInstanceEventInfo(object sender, KeyEventArgs e) =>
Handler.InstanceEventInfo(sender, e);
}
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
' Attach an instance handler on componentWrapper that will be invoked by handled KeyDown events.
componentWrapper.[AddHandler](KeyDownEvent, New RoutedEventHandler(AddressOf InstanceEventInfo),
handledEventsToo:=True)
End Sub
' The handler attached to componentWrapper in XAML.
Public Sub HandlerInstanceEventInfo(sender As Object, e As KeyEventArgs)
InstanceEventInfo(sender, e)
End Sub
End Class
arka planda kod uygulaması ComponentWrapper
sonraki bölümde gösterilir.
Statik sınıf olay işleyicileri
Bir sınıfın statik oluşturucusunda yöntemini çağırarak RegisterClassHandler statik sınıf olay işleyicileri ekleyebilirsiniz. Sınıf hiyerarşisindeki her sınıf, yönlendirilen her olay için kendi statik sınıf işleyicisini kaydedebilir. Sonuç olarak, olay yolundaki belirli bir düğümde aynı olay için çağrılan birden çok statik sınıf işleyicisi olabilir. Olay için olay yolu oluşturulduğunda, her düğüm için tüm statik sınıf işleyicileri olay yoluna eklenir. Bir düğümdeki statik sınıf işleyicilerinin çağrılma sırası, en çok türetilen statik sınıf işleyicisiyle başlar ve ardından ardışık her temel sınıftan statik sınıf işleyicileri gelir.
parametresi ayarlı true
aşırı yükleme kullanılarak RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) kaydedilen statik sınıf olay işleyicileri hem işlenmeyen handledEventsToo
hem de işlenen yönlendirilmiş olaylara yanıt verir.
Statik sınıf işleyicileri genellikle yalnızca işlenmeyen olaylara yanıt vermek için kaydedilir. Bu durumda, düğümdeki türetilmiş bir sınıf işleyicisi bir olayı işlendi olarak işaretlerse, bu olay için temel sınıf işleyicileri çağrılmayacak. Bu senaryoda temel sınıf işleyicisi, türetilmiş sınıf işleyicisi tarafından etkili bir şekilde değiştirilir. Temel sınıf işleyicileri genellikle görsel görünüm, durum mantığı, giriş işleme ve komut işleme gibi alanlarda denetim tasarımına katkıda bulunur, bu nedenle bunları değiştirme konusunda dikkatli olun. Bir olayı işlendi olarak işaretlemeyen türetilmiş sınıf işleyicileri, bunları değiştirmek yerine temel sınıf işleyicilerini tamamlar.
Aşağıdaki kod örneği, önceki XAML'de başvuruda bulunan özel denetimin sınıf hiyerarşisini ComponentWrapper
gösterir. sınıfı ComponentWrapper
sınıfından ComponentWrapperBase
türetilir ve bu da sınıfından StackPanel türetilir. RegisterClassHandler
ve ComponentWrapperBase
sınıflarının statik oluşturucusunda kullanılan yöntemi, bu sınıfların ComponentWrapper
her biri için statik sınıf olay işleyicisi kaydeder. WPF olay sistemi statik sınıf işleyicisinin ComponentWrapper
önünde statik sınıf işleyicisini ComponentWrapperBase
çağırır.
public class ComponentWrapper : ComponentWrapperBase
{
static ComponentWrapper()
{
// Class event handler implemented in the static constructor.
EventManager.RegisterClassHandler(typeof(ComponentWrapper), KeyDownEvent,
new RoutedEventHandler(Handler.ClassEventInfo_Static));
}
// Class event handler that overrides a base class virtual method.
protected override void OnKeyDown(KeyEventArgs e)
{
Handler.ClassEventInfo_Override(this, e);
// Call the base OnKeyDown implementation on ComponentWrapperBase.
base.OnKeyDown(e);
}
}
public class ComponentWrapperBase : StackPanel
{
// Class event handler implemented in the static constructor.
static ComponentWrapperBase()
{
EventManager.RegisterClassHandler(typeof(ComponentWrapperBase), KeyDownEvent,
new RoutedEventHandler(Handler.ClassEventInfoBase_Static));
}
// Class event handler that overrides a base class virtual method.
protected override void OnKeyDown(KeyEventArgs e)
{
Handler.ClassEventInfoBase_Override(this, e);
e.Handled = true;
Debug.WriteLine("The KeyDown routed event is marked as handled.");
// Call the base OnKeyDown implementation on StackPanel.
base.OnKeyDown(e);
}
}
Public Class ComponentWrapper
Inherits ComponentWrapperBase
Shared Sub New()
' Class event handler implemented in the static constructor.
EventManager.RegisterClassHandler(GetType(ComponentWrapper), KeyDownEvent,
New RoutedEventHandler(AddressOf ClassEventInfo_Static))
End Sub
' Class event handler that overrides a base class virtual method.
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
ClassEventInfo_Override(Me, e)
' Call the base OnKeyDown implementation on ComponentWrapperBase.
MyBase.OnKeyDown(e)
End Sub
End Class
Public Class ComponentWrapperBase
Inherits StackPanel
Shared Sub New()
' Class event handler implemented in the static constructor.
EventManager.RegisterClassHandler(GetType(ComponentWrapperBase), KeyDownEvent,
New RoutedEventHandler(AddressOf ClassEventInfoBase_Static))
End Sub
' Class event handler that overrides a base class virtual method.
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
ClassEventInfoBase_Override(Me, e)
e.Handled = True
Debug.WriteLine("The KeyDown event is marked as handled.")
' Call the base OnKeyDown implementation on StackPanel.
MyBase.OnKeyDown(e)
End Sub
End Class
Bu kod örneğindeki geçersiz kılma sınıfı olay işleyicilerinin arka planda kod uygulaması sonraki bölümde ele alınmalıdır.
Sınıf olay işleyicilerini geçersiz kılma
Bazı görsel öğe temel sınıfları, genel yönlendirilmiş giriş olaylarının her biri için boş On olay adı> ve OnPreview<olay adı> sanal yöntemlerini kullanıma<sunar. Örneğin, UIElement ve OnPreviewKeyDown sanal olay işleyicilerini ve diğerlerini uygularOnKeyDown. Türetilmiş sınıflarınız için geçersiz kılma sınıfı olay işleyicilerini uygulamak için temel sınıf sanal olay işleyicilerini geçersiz kılabilirsiniz. Örneğin, sanal yöntemi geçersiz kılarak türetilmiş herhangi bir UIElement
sınıfta olay için DragEnter bir geçersiz kılma sınıfı işleyicisi OnDragEnter ekleyebilirsiniz. Temel sınıf sanal yöntemlerini geçersiz kılma, sınıf işleyicilerini statik bir oluşturucuya kaydetmekten daha basit bir yoldur. Geçersiz kılma içinde olayları oluşturabilir, örneklerdeki öğe özelliklerini değiştirmek için sınıfa özgü mantık başlatabilir, olayı işlenmiş olarak işaretleyebilir veya başka olay işleme mantığı gerçekleştirebilirsiniz.
Statik sınıf olay işleyicilerinden farklı olarak WPF olay sistemi yalnızca sınıf hiyerarşisindeki en türetilmiş sınıf için geçersiz kılma sınıf olay işleyicilerini çağırır. Daha sonra bir sınıf hiyerarşisindeki en türetilmiş sınıf, sanal yöntemin temel uygulamasını çağırmak için base anahtar sözcüğünü kullanabilir. Çoğu durumda, bir olayı işlenmiş olarak işaretleyip işaretlemediğinize bakılmaksızın temel uygulamayı çağırmanız gerekir. Yalnızca sınıfınızın varsa temel uygulama mantığını değiştirme gereksinimi varsa temel uygulamayı çağırmayı atlamalısınız. Geçersiz kılma kodunuz öncesinde veya sonrasında temel uygulamayı çağırmak, uygulamanızın doğasına bağlıdır.
Yukarıdaki kod örneğinde, hem ve ComponentWrapper
ComponentWrapperBase
sınıflarında temel sınıf OnKeyDown
sanal yöntemi geçersiz kılınmış. WPF olay sistemi yalnızca geçersiz kılma sınıfı olay işleyicisini ComponentWrapper.OnKeyDown
çağırdığından, bu işleyici geçersiz kılma sınıfı olay işleyicisini çağırmak ComponentWrapperBase.OnKeyDown
için kullanır base.OnKeyDown(e)
ve bu da sanal yöntemi çağırmak StackPanel.OnKeyDown
için kullanırbase.OnKeyDown(e)
. Yukarıdaki kod örneğindeki olayların sırası:
- öğesine eklenen
componentWrapper
örnek işleyicisi, yönlendirilen olay tarafındanPreviewKeyDown
tetiklendi. - öğesine eklenen
componentWrapper
statik sınıf işleyicisi, yönlendirilen olay tarafındanKeyDown
tetikleniyor. - öğesine eklenen
componentWrapperBase
statik sınıf işleyicisi, yönlendirilen olay tarafındanKeyDown
tetikleniyor. - öğesine eklenen
componentWrapper
geçersiz kılma sınıfı işleyicisi, yönlendirilen olay tarafındanKeyDown
tetikleniyor. - öğesine eklenen
componentWrapperBase
geçersiz kılma sınıfı işleyicisi, yönlendirilen olay tarafındanKeyDown
tetikleniyor. - Yönlendirilen
KeyDown
olay işlendi olarak işaretlenir. - öğesine eklenen
componentWrapper
örnek işleyicisi, yönlendirilen olay tarafındanKeyDown
tetiklendi. İşleyici, parametresi olarakhandledEventsToo
ayarlanmış olaraktrue
kaydedildi.
Bileşik denetimlerde giriş olayı gizleme
Bazı bileşik denetimler, daha fazla bilgi taşıyan veya daha belirli bir davranışa işaret eden özelleştirilmiş bir üst düzey olayla değiştirmek için bileşen düzeyinde giriş olaylarını gizler. Bileşik denetim, birden çok pratik denetimden veya denetim temel sınıfından oluşan bir tanımdır. Klasik bir örnek, çeşitli fare olaylarını yönlendirilmiş bir Click olaya dönüştüren denetimdirButton. Button
Temel sınıf, dolaylı olarak öğesinden UIElementtüretilen şeklindedirButtonBase. Denetim girişi işleme için gereken olay altyapısının UIElement
büyük bir kısmı düzeyinde kullanılabilir. UIElement
ve MouseRightButtonDowngibi MouseLeftButtonDown çeşitli Mouse olayları kullanıma sunar. UIElement
ayrıca boş sanal yöntemleri OnMouseLeftButtonDown ve OnMouseRightButtonDown önceden kayıtlı sınıf işleyicileri olarak uygular. ButtonBase
bu sınıf işleyicilerini geçersiz kılar ve geçersiz kılma işleyicisi içinde özelliğini olarak true
ayarlar Handled ve bir Click
olay oluşturur. Çoğu dinleyici için sonuç, ve MouseRightButtonDown
olaylarının gizlenmesi MouseLeftButtonDown
ve üst düzey Click
olayın görünür olmasıdır.
Giriş olayı gizlemeyi geçici olarak çözme
Bazen tek tek denetimler içinde olay gizleme, uygulamanızdaki olay işleme mantığına müdahale edebilir. Örneğin, uygulamanız XAML kök öğesinde olay için bir işleyici eklemek için MouseLeftButtonDown XAML öznitelik söz dizimini kullandıysa, denetim olayı işlenmiş olarak işaretlediğinden Button MouseLeftButtonDown
bu işleyici çağrılmayacak. İşlenen yönlendirilmiş olay için uygulamanızın köküne yönelik öğelerin çağrılmasını istiyorsanız şunları yapabilirsiniz:
parametresi olarak ayarlanmış yöntemi
handledEventsToo
çağırarak UIElement.AddHandler(RoutedEvent, Delegate, Boolean) işleyicileritrue
ekleyin. Bu yaklaşım, ekleyecek öğe için bir nesne başvurusu aldıktan sonra olay işleyicisinin arka planda koda eklenmesini gerektirir.İşlendi olarak işaretlenen olay bir kabarcık giriş olayıysa, varsa eşleştirilmiş ö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 olay verilerini paylaşan giriş olay çiftlerini önizleme ve kabarcıklama için çalışır. Bu, olayı tamamen bastıracağı Click için öğesini işlenmiş olarak işaretlememeyePreviewMouseLeftButtonDown
dikkat edin.
Giriş olayı gizleme sorununu geçici olarak çözme örneği için bkz . Denetimler tarafından olay gizlemeye geçici bir çözüm.
Ayrıca bkz.
.NET Desktop feedback