Przegląd Zdarzenia trasowane
W tym temacie opisano koncepcję zdarzeń kierowanych w programie Windows Presentation Foundation (WPF). Temat definiuje terminologię zdarzeń kierowanych, opisuje sposób kierowania zdarzeń trasowanych przez drzewo elementów, podsumowuje sposób obsługi zdarzeń trasowanych i wprowadza sposób tworzenia własnych niestandardowych zdarzeń trasowanych.
Wymagania wstępne
W tym temacie założono, że masz podstawową wiedzę na temat środowiska uruchomieniowego języka wspólnego (CLR) i programowania obiektowego, a także koncepcji sposobu, w jaki relacje między elementami WPF mogą być koncepcyjne jako drzewo. Aby postępować zgodnie z przykładami w tym temacie, należy również zrozumieć język XAML (Extensible Application Markup Language) i wiedzieć, jak pisać bardzo podstawowe aplikacje lub strony WPF. Aby uzyskać więcej informacji, zobacz Przewodnik: Moja pierwsza aplikacja klasyczna WPF i XAML w WPF.
Co to jest zdarzenie kierowane?
Można myśleć o zdarzeniach kierowanych z perspektywy funkcjonalnej lub implementacji. Obie definicje są przedstawione tutaj, ponieważ niektóre osoby znajdują jedną lub drugą definicję bardziej przydatną.
Definicja funkcjonalna: zdarzenie kierowane jest typem zdarzenia, które może wywoływać programy obsługi na wielu odbiornikach w drzewie elementów, a nie tylko na obiekcie, który zgłosił zdarzenie.
Definicja implementacji: zdarzenie kierowane jest zdarzeniem CLR, które jest wspierane przez wystąpienie RoutedEvent klasy i jest przetwarzane przez system zdarzeń Windows Presentation Foundation (WPF).
Typowa aplikacja WPF zawiera wiele elementów. Niezależnie od tego, czy zostały utworzone w kodzie, czy zadeklarowane w języku XAML, te elementy istnieją w relacji drzewa elementów ze sobą. Trasa zdarzeń może podróżować w jednym z dwóch kierunków w zależności od definicji zdarzenia, ale zazwyczaj trasa jest przenoszona z elementu źródłowego, a następnie "bąbelki" w górę przez drzewo elementów do momentu dotarcia do korzenia drzewa elementów (zazwyczaj strony lub okna). Ta koncepcja bubbling może być znajoma, jeśli wcześniej pracowałeś z modelem obiektów DHTML.
Rozważ następujące proste drzewo elementów:
<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>
To drzewo elementów tworzy coś podobnego do następującego:
W tym uproszczonym drzewie elementów źródło Click zdarzenia jest jednym z Button elementów, a w zależności Button od tego, która z nich została kliknięta, jest pierwszym elementem, który ma możliwość obsługi zdarzenia. Jeśli jednak program obsługi nie jest dołączony do Button działań w przypadku zdarzenia, zdarzenie będzie bąbelkowe w górę do Button elementu nadrzędnego w drzewie elementów, czyli StackPanel. Potencjalnie bąbelki zdarzenia do Border, a następnie poza elementem głównym strony drzewa elementów (nie są wyświetlane).
Innymi słowy, trasa zdarzeń dla tego Click zdarzenia to:
Button-->StackPanel-->Border--...>
Scenariusze najwyższego poziomu dla zdarzeń trasowanych
Poniżej przedstawiono krótkie podsumowanie scenariuszy, które motywowały koncepcję zdarzenia kierowanego i dlaczego typowe zdarzenie CLR nie było odpowiednie dla tych scenariuszy:
Kompozycja kontrolna i hermetyzacja: Różne kontrolki w WPF mają bogaty con tryb namiotu l. Można na przykład umieścić obraz wewnątrz Buttonobiektu , który skutecznie rozszerza drzewo wizualne przycisku. Jednak dodany obraz nie może przerwać działania testowania trafień, które powoduje, że przycisk reaguje na Click jego zawartość, nawet jeśli użytkownik kliknie piksele, które są technicznie częścią obrazu.
Pojedyncze punkty załączników programu obsługi: w formularzach Systemu Windows należy dołączyć tę samą procedurę obsługi wiele razy do przetwarzania zdarzeń, które mogą być wywoływane z wielu elementów. Zdarzenia trasowane umożliwiają dołączenie tej procedury obsługi tylko raz, jak pokazano w poprzednim przykładzie, i użycie logiki obsługi w celu określenia, skąd pochodzi zdarzenie, jeśli jest to konieczne. Na przykład może to być procedura obsługi wcześniej pokazanego kodu XAML:
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
Obsługa klas: zdarzenia kierowane zezwalają na statyczną procedurę obsługi zdefiniowaną przez klasę. Ta procedura obsługi klas ma możliwość obsługi zdarzenia, zanim będzie można obsługiwać wszystkie dołączone programy obsługi wystąpień.
Odwoływanie się do zdarzenia bez odbicia: niektóre techniki kodu i znaczników wymagają sposobu identyfikowania określonego zdarzenia. Zdarzenie kierowane tworzy RoutedEvent pole jako identyfikator, który zapewnia niezawodną technikę identyfikacji zdarzeń, która nie wymaga odbicia statycznego ani czasu wykonywania.
Jak są implementowane zdarzenia trasowane
Zdarzenie kierowane to zdarzenie CLR, które jest wspierane przez wystąpienie RoutedEvent klasy i zarejestrowane w systemie zdarzeń WPF. RoutedEvent Wystąpienie uzyskane z rejestracji jest zwykle zachowywane jako public
static
readonly
element członkowski pola klasy, która rejestruje się, a tym samym "jest właścicielem" kierowanego zdarzenia. Połączenie z identycznie nazwanym zdarzeniem CLR (nazywane czasem zdarzeniem "otoki") jest realizowane przez zastąpienie add
implementacji i remove
dla zdarzenia CLR. Zazwyczaj add
remove
i są pozostawione jako niejawne domyślne, które używa odpowiedniej składni zdarzeń specyficznych dla języka do dodawania i usuwania programów obsługi tego zdarzenia. Mechanizm tworzenia kopii zapasowych zdarzeń kierowanych i połączenia jest koncepcyjnie podobny do sposobu, w jaki właściwość zależności jest właściwością CLR wspieraną przez klasę i zarejestrowaną w DependencyProperty systemie właściwości WPF.
Poniższy przykład przedstawia deklarację niestandardowego zdarzenia kierowanego Tap
, w tym rejestrację i ekspozycję pola identyfikatora RoutedEvent oraz add
remove
implementacje zdarzenia Tap
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
Programy obsługi zdarzeń trasowanych i XAML
Aby dodać program obsługi dla zdarzenia przy użyciu języka XAML, należy zadeklarować nazwę zdarzenia jako atrybut w elemecie, który jest odbiornikiem zdarzeń. Wartość atrybutu to nazwa zaimplementowanej metody obsługi, która musi istnieć w częściowej klasie pliku za pomocą kodu.
<Button Click="b1SetColor">button</Button>
Składnia XAML służąca do dodawania standardowych procedur obsługi zdarzeń CLR jest taka sama w przypadku dodawania procedur obsługi zdarzeń kierowanych, ponieważ naprawdę dodajesz programy obsługi do otoki zdarzeń CLR, która ma implementację zdarzeń kierowanych poniżej. Aby uzyskać więcej informacji na temat dodawania programów obsługi zdarzeń w języku XAML, zobacz XAML w WPF.
Strategie routingu
Zdarzenia kierowane używają jednej z trzech strategii routingu:
Bubbling: Wywoływane są programy obsługi zdarzeń w źródle zdarzeń. Następnie kierowane zdarzenie kieruje do kolejnych elementów nadrzędnych do momentu osiągnięcia katalogu głównego drzewa elementów. Większość zdarzeń kierowanych używa strategii routingu bubbling. Zdarzenia kierowane przez bubbling są zwykle używane do zgłaszania zmian danych wejściowych lub stanu z różnych kontrolek lub innych elementów interfejsu użytkownika.
Bezpośredni: tylko sam element źródłowy daje możliwość wywoływania programów obsługi w odpowiedzi. Jest to analogiczne do "routingu", którego używa windows Forms dla zdarzeń. Jednak w przeciwieństwie do standardowego zdarzenia CLR, bezpośrednie zdarzenia kierowane obsługują obsługę klas (obsługa klas jest wyjaśniona w nadchodzącej sekcji) i może być używana przez EventSetter EventTriggeri .
Tunelowanie: początkowo wywoływane są programy obsługi zdarzeń w katalogu głównym drzewa elementów. Zdarzenie kierowane następnie podróżuje trasą przez kolejne elementy podrzędne wzdłuż trasy w kierunku elementu węzła, który jest źródłem zdarzeń kierowanych (element, który podniósł kierowane zdarzenie). Zdarzenia kierowane przez tunelowanie są często używane lub obsługiwane w ramach komponowania dla kontrolki, tak aby zdarzenia z części złożonych mogły być celowo pomijane lub zastępowane zdarzeniami specyficznymi dla pełnej kontroli. Zdarzenia wejściowe udostępniane w WPF często są implementowane jako para tunelowania/bubbling. Zdarzenia tunelowania są również czasami nazywane zdarzeniami w wersji zapoznawczej ze względu na konwencję nazewnictwa używaną dla par.
Dlaczego warto używać zdarzeń trasowanych?
Jako deweloper aplikacji nie zawsze musisz wiedzieć ani zadbać o to, aby zdarzenie, które obsługujesz, zostało zaimplementowane jako zdarzenie kierowane. Zdarzenia kierowane mają specjalne zachowanie, ale takie zachowanie jest w dużej mierze niewidoczne, jeśli obsługujesz zdarzenie w elemecie, w którym jest wywoływany.
Gdzie zdarzenia kierowane stają się zaawansowane, to jeśli używasz dowolnego z sugerowanych scenariuszy: definiowanie typowych procedur obsługi we wspólnym katalogu głównym, komponowanie własnej kontrolki lub definiowanie własnej niestandardowej klasy sterowania.
Odbiorniki zdarzeń kierowanych i kierowane źródła zdarzeń nie muszą współużytkować wspólnego zdarzenia w hierarchii. Dowolny UIElement lub ContentElement może być odbiornikiem zdarzeń dla dowolnego zdarzenia kierowanego. W związku z tym można użyć pełnego zestawu zdarzeń kierowanych dostępnych w całym zestawie interfejsu API pracy jako koncepcyjnego "interfejsu", w którym różne elementy w aplikacji mogą wymieniać informacje o zdarzeniach. Ta koncepcja "interfejsu" dla zdarzeń kierowanych ma szczególnie zastosowanie w przypadku zdarzeń wejściowych.
Zdarzenia trasowane mogą również służyć do komunikowania się za pośrednictwem drzewa elementów, ponieważ dane zdarzenia dla zdarzenia są utrwalane dla każdego elementu trasy. Jeden element może zmienić coś w danych zdarzenia i ta zmiana będzie dostępna dla następnego elementu w trasie.
Poza aspektem routingu istnieją dwa inne przyczyny, dla których każde zdarzenie WPF może zostać zaimplementowane jako zdarzenie kierowane zamiast standardowego zdarzenia CLR. Jeśli wdrażasz własne zdarzenia, możesz również rozważyć następujące zasady:
Niektóre funkcje stylów I szablonów WPF, takie jak EventSetter i EventTrigger wymagają, aby zdarzenie, do których się odwoływało, było zdarzeniem kierowanym. Jest to scenariusz identyfikatora zdarzeń wymieniony wcześniej.
Zdarzenia kierowane obsługują mechanizm obsługi klas, w którym klasa może określać metody statyczne, które mają możliwość obsługi zdarzeń kierowanych przed uzyskaniem dostępu do nich przez wszystkie zarejestrowane programy obsługi wystąpień. Jest to bardzo przydatne w projekcie sterowania, ponieważ klasa może wymuszać zachowania klasy sterowanej zdarzeniami, których nie można przypadkowo pominąć przez obsługę zdarzenia w wystąpieniu.
Każda z powyższych kwestii została omówiona w oddzielnej sekcji tego tematu.
Dodawanie i implementowanie programu obsługi zdarzeń dla zdarzenia kierowanego
Aby dodać program obsługi zdarzeń w języku XAML, wystarczy dodać nazwę zdarzenia do elementu jako atrybut i ustawić wartość atrybutu jako nazwę procedury obsługi zdarzeń, która implementuje odpowiedni delegat, jak w poniższym przykładzie.
<Button Click="b1SetColor">button</Button>
b1SetColor
to nazwa zaimplementowanej procedury obsługi zawierającej kod, który obsługuje Click zdarzenie. b1SetColor
musi mieć ten sam podpis co RoutedEventHandler delegat, który jest pełnomocnikem programu obsługi zdarzeń dla Click zdarzenia. Pierwszy parametr wszystkich delegatów procedury obsługi zdarzeń kierowanych określa element, do którego jest dodawany program obsługi zdarzeń, a drugi parametr określa dane zdarzenia.
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 to podstawowy delegat procedury obsługi zdarzeń kierowanych. W przypadku zdarzeń kierowanych, które są wyspecjalizowane w przypadku niektórych kontrolek lub scenariuszy, delegaci do użycia dla procedur obsługi zdarzeń kierowanych mogą również stać się bardziej wyspecjalizowane, dzięki czemu mogą przesyłać wyspecjalizowane dane zdarzeń. Na przykład w typowym scenariuszu wejściowym można obsłużyć DragEnter zdarzenie kierowane. Procedura obsługi powinna implementować delegata DragEventHandler . Korzystając z najbardziej określonego delegata, można przetworzyć DragEventArgs element w procedurze obsługi i odczytać Data właściwość, która zawiera ładunek schowka operacji przeciągania.
Pełny przykład sposobu dodawania procedury obsługi zdarzeń do elementu przy użyciu języka XAML można znaleźć w temacie Handle a Routed Event (Obsługa zdarzenia trasowanego).
Dodawanie procedury obsługi dla zdarzenia kierowanego w aplikacji utworzonej w kodzie jest proste. Procedury obsługi zdarzeń trasowanych można zawsze dodawać za pomocą metody AddHandler pomocniczej (która jest tą samą metodą, w której istniejące wywołania zapasowe dla elementu add
. Jednak istniejące zdarzenia kierowane przez WPF zwykle mają implementacje add
remove
i logikę, które umożliwiają obsługę kierowanych zdarzeń przez składnię zdarzeń specyficznych dla języka, co jest bardziej intuicyjną składnią niż metoda pomocnika. Poniżej przedstawiono przykładowe użycie metody pomocniczej:
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
W następnym przykładzie pokazano składnię operatora języka C# (Język Visual Basic ma nieco inną składnię operatora ze względu na obsługę wyłudzeń):
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
Aby zapoznać się z przykładem dodawania procedury obsługi zdarzeń w kodzie, zobacz Dodawanie programu obsługi zdarzeń przy użyciu kodu.
Jeśli używasz języka Visual Basic, możesz również użyć słowa kluczowego Handles
, aby dodać programy obsługi w ramach deklaracji programu obsługi. Aby uzyskać więcej informacji, zobacz Visual Basic i WPF Event Handling (Obsługa zdarzeń w języku Visual Basic i WPF).
Koncepcja obsługi
Wszystkie zdarzenia kierowane mają wspólną klasę bazową danych zdarzeń, RoutedEventArgs. RoutedEventArgsHandled definiuje właściwość , która przyjmuje wartość logiczną. Celem Handled właściwości jest włączenie dowolnego programu obsługi zdarzeń wzdłuż trasy, aby oznaczyć zdarzenie kierowane zgodnie z procedurą obsługi, ustawiając wartość Handled na true
. Po przetworzeniu przez program obsługi w jednym elemenie wzdłuż trasy dane zdarzeń udostępnionych są ponownie zgłaszane do każdego odbiornika wzdłuż trasy.
Wartość Handled ma wpływ na sposób raportowania lub przetwarzania zdarzenia kierowanego w miarę przechodzenia dalej wzdłuż trasy. Jeśli Handled dane zdarzenia są true
w danych zdarzenia kierowanego, programy obsługi, które nasłuchują tego zdarzenia kierowanego w innych elementach, zwykle nie są już wywoływane dla tego konkretnego wystąpienia zdarzenia. Dotyczy to zarówno procedur obsługi dołączonych w języku XAML, jak i procedur obsługi dodanych przez składnie załączników obsługi zdarzeń specyficznych dla języka, takich jak +=
lub Handles
. W przypadku najbardziej typowych scenariuszy obsługi oznaczanie zdarzenia jako obsługiwanego przez ustawienie Handled true
spowoduje "zatrzymanie" routingu dla trasy tunelowania lub trasy bubbling, a także dla każdego zdarzenia obsługiwanego w punkcie trasy przez program obsługi klas.
Istnieje jednak mechanizm "handledEventsToo", w którym odbiorniki mogą nadal uruchamiać programy obsługi w odpowiedzi na kierowane zdarzenia, w których Handled znajdują się true
dane zdarzenia. Innymi słowy, trasa zdarzeń nie jest naprawdę zatrzymana przez oznaczenie danych zdarzenia jako obsłużonych. Mechanizm handledEventsToo można używać tylko w kodzie lub w elemecie EventSetter:
W kodzie zamiast używać składni zdarzeń specyficznych dla języka, która działa dla ogólnych zdarzeń CLR, wywołaj metodę WPF, aby dodać procedurę AddHandler(RoutedEvent, Delegate, Boolean) obsługi. Określ wartość
handledEventsToo
jakotrue
.W elemecie EventSetterustaw HandledEventsToo atrybut na
true
.
Oprócz zachowania, które Handled stan generuje w zdarzeniach kierowanych, pojęcie Handled ma wpływ na sposób projektowania aplikacji i pisania kodu procedury obsługi zdarzeń. Można koncepcyjnie Handled określić jako prosty protokół, który jest udostępniany przez zdarzenia kierowane. Dokładnie tak, jak używasz tego protokołu, należy do Ciebie, ale koncepcyjny projekt dotyczący sposobu użycia wartości Handled jest następujący:
Jeśli zdarzenie kierowane jest oznaczone jako obsługiwane, nie musi być ponownie obsługiwane przez inne elementy tej trasy.
Jeśli zdarzenie kierowane nie jest oznaczone jako obsługiwane, inne odbiorniki, które wcześniej wzdłuż trasy wybrały opcję niezarejestrowania programu obsługi, lub programów obsługi, które zostały zarejestrowane, nie chcą manipulować danymi zdarzenia i ustawić na Handled
true
wartość . (Oczywiście jest możliwe, że bieżący odbiornik jest pierwszym punktem w trasie). Programy obsługi na bieżącym odbiorniku mają teraz trzy możliwe kursy akcji:Nie podejmij żadnych działań; zdarzenie pozostaje nieobsługiwane, a zdarzenie kieruje do następnego odbiornika.
Wykonaj kod w odpowiedzi na zdarzenie, ale upewnij się, że podjęta akcja nie była wystarczająco znacząca, aby uzasadnić oznaczenie zdarzenia zgodnie z obsługą. Zdarzenie kieruje do następnego odbiornika.
Wykonaj kod w odpowiedzi na zdarzenie. Oznacz zdarzenie jako obsłużone w danych zdarzenia przekazanych do programu obsługi, ponieważ podjęta akcja została uznana za wystarczająco znaczącą, aby uzasadnić oznaczenie jako obsługiwane. Zdarzenie nadal kieruje się do następnego odbiornika, ale z Handled=
true
danymi zdarzeń, więc tylkohandledEventsToo
odbiorniki mają możliwość wywołania dalszych procedur obsługi.
Ten projekt koncepcyjny jest wzmacniany przez opisane wcześniej zachowanie routingu: jest to trudniejsze (chociaż nadal możliwe w kodzie lub stylach) dołączanie procedur obsługi dla zdarzeń trasowanych, które są wywoływane, nawet jeśli poprzednia procedura obsługi wzdłuż trasy ma już ustawioną wartość Handled true
.
Aby uzyskać więcej informacji na temat Handledobsługi klas kierowanych zdarzeń i zaleceń dotyczących tego, kiedy jest to właściwe, aby oznaczyć zdarzenie kierowane jako Handled, zobacz Oznaczanie zdarzeń trasowanych jako obsługiwane i Obsługa klas.
W aplikacjach dość często zdarza się po prostu obsługiwać rozsyłane zdarzenie na obiekcie, który go podniósł, a nie być zaniepokojony charakterystyką routingu zdarzenia w ogóle. Jednak nadal dobrym rozwiązaniem jest oznaczenie zdarzenia kierowanego jako obsługiwanego w danych zdarzenia, aby zapobiec nieprzewidzianym skutkom ubocznym na wypadek, gdyby element, który jest dalej w drzewie elementów, również ma program obsługi dołączony do tego samego zdarzenia trasy.
Programy obsługi klas
Jeśli definiujesz klasę, która pochodzi w jakiś sposób z DependencyObjectklasy , możesz również zdefiniować i dołączyć procedurę obsługi klas dla zdarzenia kierowanego, które jest zadeklarowanym lub dziedziczonym elementem członkowskim zdarzenia klasy. Procedury obsługi klas są wywoływane przed wszystkimi procedurami obsługi odbiornika wystąpień dołączonymi do wystąpienia tej klasy za każdym razem, gdy kierowane zdarzenie osiągnie wystąpienie elementu w swojej trasie.
Niektóre kontrolki WPF mają nieodłączną obsługę klas dla niektórych zdarzeń trasowanych. Może to spowodować pojawienie się na zewnątrz, że zdarzenie kierowane nie jest nigdy zgłaszane, ale w rzeczywistości jest obsługiwane przez klasy, a kierowane zdarzenie może być potencjalnie obsługiwane przez programy obsługi wystąpień, jeśli używasz pewnych technik. Ponadto wiele klas bazowych i kontrolek uwidacznia metody wirtualne, które mogą służyć do zastępowania zachowania obsługi klas. Aby uzyskać więcej informacji na temat sposobu obejścia niepożądanej obsługi klas i definiowania własnej obsługi klas w klasie niestandardowej, zobacz Oznaczanie zdarzeń trasowanych jako obsługiwane i Obsługa klas.
Dołączone zdarzenia w WPF
Język XAML definiuje również specjalny typ zdarzenia nazywany dołączonym zdarzeniem. Dołączone zdarzenie umożliwia dodanie procedury obsługi dla określonego zdarzenia do dowolnego elementu. Element obsługujący zdarzenie nie musi definiować ani dziedziczyć dołączonego zdarzenia, ani obiektu, który potencjalnie podnosi zdarzenie, ani wystąpienia obsługi docelowej, ani nie musi definiować ani w inny sposób "być właścicielem" tego zdarzenia jako elementu członkowskiego klasy.
System wejściowy WPF intensywnie używa dołączonych zdarzeń. Jednak prawie wszystkie te dołączone zdarzenia są przekazywane za pośrednictwem elementów podstawowych. Zdarzenia wejściowe są następnie wyświetlane jako równoważne zdarzenia nieprzyłączone trasowane, które są elementami członkowskimi klasy elementu podstawowego. Na przykład bazowe dołączone zdarzenie można łatwiej obsłużyć na dowolnym UIElement danym za pomocą polecenia MouseDown , UIElement zamiast radzić sobie z dołączoną składnią zdarzeń Mouse.MouseDown w języku XAML lub kodzie.
Aby uzyskać więcej informacji na temat dołączonych zdarzeń w WPF, zobacz Omówienie dołączonych zdarzeń.
Kwalifikowane nazwy zdarzeń w języku XAML
Inne użycie składni podobne do typename.Składnia zdarzenia dołączonego zdarzenia eventname , ale nie jest ściśle mówiąc, dołączone użycie zdarzenia jest dołączane podczas dołączania programów obsługi dla zdarzeń kierowanych, które są wywoływane przez elementy podrzędne. Programy obsługi są dołączane do wspólnego elementu nadrzędnego, aby korzystać z routingu zdarzeń, mimo że wspólny element nadrzędny może nie mieć odpowiedniego zdarzenia kierowanego jako członek. Rozważ ponownie ten przykład:
<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>
W tym miejscu odbiornik elementu nadrzędnego, w którym jest dodawany program obsługi, jest elementem StackPanel. Dodaje jednak program obsługi dla zadeklarowanego zdarzenia trasy i zostanie zgłoszony przez Button klasę (ButtonBase faktycznie, ale dostępny dla Button dziedziczenia). Button "jest właścicielem" zdarzenia, ale kierowany system zdarzeń zezwala na obsługę wszystkich kierowanych zdarzeń do dołączenia do dowolnego UIElement odbiornika lub ContentElement wystąpienia, który w przeciwnym razie może dołączyć odbiorniki dla zdarzenia środowiska uruchomieniowego języka wspólnego (CLR). Domyślna przestrzeń nazw xmlns dla tych kwalifikowanych nazw atrybutów zdarzeń jest zazwyczaj domyślną przestrzenią nazw xmlns WPF, ale można również określić prefiksowane przestrzenie nazw dla niestandardowych zdarzeń trasowanych. Aby uzyskać więcej informacji na temat xmlns, zobacz Przestrzenie nazw XAML i Mapowanie przestrzeni nazw dla WPF XAML.
Zdarzenia wejściowe WPF
Jedną z częstych aplikacji kierowanych zdarzeń na platformie WPF są zdarzenia wejściowe. W WPF tunelowanie trasowanych nazw zdarzeń jest poprzedzone słowem "Wersja zapoznawcza" zgodnie z konwencją. Zdarzenia wejściowe często występują w parach, z jednym jest zdarzeniem bubbling i drugim zdarzeniem tunelowania. Na przykład KeyDown zdarzenie i PreviewKeyDown zdarzenie mają ten sam podpis, a pierwszy jest zdarzeniem wejściowym bubbling, a drugim zdarzeniem wejściowym tunelowania. Czasami zdarzenia wejściowe mają tylko wersję bubbling lub być może tylko wersję kierowaną bezpośrednio. W dokumentacji przekierowane tematy zdarzeń odwołujące się do podobnych trasowanych zdarzeń z alternatywnymi strategiami routingu, jeśli takie zdarzenia kierowane istnieją, a sekcje na zarządzanych stronach referencyjnych wyjaśniają strategię routingu każdego kierowanego zdarzenia.
Zdarzenia wejściowe WPF, które występują w parach, są implementowane tak, aby pojedyncza akcja użytkownika z danych wejściowych, takich jak naciśnięcie przycisku myszy, spowoduje podniesienie obu kierowanych zdarzeń pary w sekwencji. Najpierw zdarzenie tunelowania jest zgłaszane i podróżuje swoją trasą. Następnie impreza bubbling jest podniesiona i podróżuje swoją trasą. Dwa zdarzenia dosłownie współużytkują to samo wystąpienie danych zdarzenia, ponieważ RaiseEvent wywołanie metody w klasie implementowania, która wywołuje zdarzenie bubbling nasłuchuje danych zdarzenia z zdarzenia tunelowania i ponownie używa go w nowym zgłoszonym zdarzeniu. Odbiorniki z procedurami obsługi zdarzenia tunelowania mają pierwszą okazję do oznaczania obsługiwanego zdarzenia kierowanego (najpierw procedury obsługi klas, a następnie procedury obsługi wystąpień). Jeśli element wzdłuż trasy tunelowania oznaczył zdarzenie kierowane zgodnie z obsługą, dane zdarzeń już obsługiwane są wysyłane dla zdarzenia bubbling, a typowe programy obsługi dołączone do równoważnych zdarzeń wejściowych nie będą wywoływane. Na zewnątrz wystąpień będzie tak, jakby obsłużone wydarzenie bubbling nie zostało nawet podniesione. To zachowanie obsługi jest przydatne w przypadku komposiowania kontrolek, gdzie można chcieć, aby wszystkie zdarzenia wejściowe oparte na teście trafień lub zdarzenia wejściowe oparte na fokusie były zgłaszane przez ostateczną kontrolkę, a nie jej części złożone. Ostatni element kontrolki jest bliżej katalogu głównego w komponowaniu i dlatego ma możliwość obsługi zdarzenia tunelowania najpierw i być może zastąpić to zdarzenie kierowane bardziej specyficznym dla kontroli, w ramach kodu, który wspiera klasę sterowania.
Jako ilustracja sposobu działania przetwarzania zdarzeń wejściowych należy wziąć pod uwagę następujący przykład zdarzenia wejściowego. Na poniższej ilustracji leaf element #2
drzewa jest źródłem zdarzenia , PreviewMouseDown
a następnie MouseDown
:
Kolejność przetwarzania zdarzeń jest następująca:
PreviewMouseDown
(tunel) w elemedycie głównym.PreviewMouseDown
(tunel) w elemecie pośrednim #1.PreviewMouseDown
(tunel) w elemecie źródłowym #2.MouseDown
(bąbelek) w elemecie źródłowym #2.MouseDown
(bąbelek) w elemecie pośrednim #1.MouseDown
(bąbelek) w elemecie głównym.
Delegat procedury obsługi zdarzeń kierowanych zawiera odwołania do dwóch obiektów: obiektu, który wywołał zdarzenie i obiektu, w którym wywoływano procedurę obsługi. Obiekt, w którym wywoływano procedurę obsługi, jest obiektem zgłoszonym sender
przez parametr . Obiekt, w którym zdarzenie zostało zgłoszone po raz pierwszy, jest zgłaszany przez Source właściwość w danych zdarzenia. Zdarzenie kierowane można nadal zgłaszać i obsługiwać przez ten sam obiekt, w takim przypadku sender
i Source są identyczne (dotyczy to kroków 3 i 4 na przykładowej liście przetwarzania zdarzeń).
Ze względu na tunelowanie i bubbling elementy nadrzędne odbierają zdarzenia wejściowe, w których Source element jest jednym z ich elementów podrzędnych. Jeśli ważne jest, aby wiedzieć, jaki jest element źródłowy, możesz zidentyfikować element źródłowy, korzystając Source z właściwości .
Zwykle po oznaczeniu Handledzdarzenia wejściowego dalsze procedury obsługi nie są wywoływane. Zazwyczaj należy oznaczyć zdarzenia wejściowe tak, jak tylko wywoływana jest procedura obsługi, która odpowiada logicznej obsłudze zdarzenia wejściowego specyficznego dla aplikacji.
Wyjątkiem od tej ogólnej instrukcji dotyczącej Handled stanu jest to, że programy obsługi zdarzeń wejściowych, które są zarejestrowane w celu celowego ignorowania Handled stanu danych zdarzenia, nadal będą wywoływane wzdłuż każdej trasy. Aby uzyskać więcej informacji, zobacz Podgląd zdarzeń lub Oznaczanie zdarzeń trasowanych jako obsługiwane i Obsługa klas.
Udostępniony model danych zdarzeń między zdarzeniami tunelowania i bubbling oraz sekwencyjnym podnoszeniem pierwszego tunelowania, a następnie zdarzeniami bubbling, nie jest pojęciem, które jest ogólnie prawdziwe dla wszystkich kierowanych zdarzeń. To zachowanie jest specjalnie implementowane przez sposób, w jaki urządzenia wejściowe WPF wybierają wywoływanie i łączenie par zdarzeń wejściowych. Implementowanie własnych zdarzeń wejściowych jest zaawansowanym scenariuszem, ale możesz również skorzystać z tego modelu dla własnych zdarzeń wejściowych.
Niektóre klasy decydują się na obsługę określonych zdarzeń wejściowych, zwykle z zamiarem ponownego zdefiniowania tego, co określone zdarzenie wejściowe oparte na użytkowniku oznacza w ramach tej kontrolki i podnosząc nowe zdarzenie. Aby uzyskać więcej informacji, zobacz Oznaczanie zdarzeń trasowanych jako obsługiwane i Obsługa klas.
Aby uzyskać więcej informacji na temat danych wejściowych i sposobu interakcji danych wejściowych i zdarzeń w typowych scenariuszach aplikacji, zobacz Omówienie danych wejściowych.
EventSetters i EventTriggers
W stylach można uwzględnić wstępnie zadeklarowaną składnię obsługi zdarzeń XAML w adiustacji przy użyciu elementu EventSetter. Po zastosowaniu stylu program obsługi, do stylu jest dodawany program obsługi, do których odwołuje się styl. Można zadeklarować EventSetter tylko dla zdarzenia kierowanego. Poniżej przedstawiono przykład. Należy pamiętać, że b1SetColor
metoda, do którego się odwołujesz, znajduje się w pliku za pomocą kodu.
<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>
Zaletą tej korzyści jest to, że styl może zawierać wiele innych informacji, które mogą być stosowane do dowolnego przycisku w aplikacji, i że EventSetter jest częścią tego stylu promuje ponowne użycie kodu nawet na poziomie znaczników. Ponadto nazwy metod abstrakcyjnych dla procedur obsługi o EventSetter jeden krok dalej od ogólnej aplikacji i znaczników strony.
Inną wyspecjalizowaną składnią, która łączy trasy zdarzenia i funkcje animacji WPF jest .EventTrigger Podobnie jak w przypadku EventSetterusługi , tylko zdarzenia kierowane mogą być używane dla elementu EventTrigger. Zazwyczaj element EventTrigger jest zadeklarowany jako część stylu, ale EventTrigger można go również zadeklarować na elementach na poziomie strony w ramach Triggers kolekcji lub w obiekcie ControlTemplate. Element EventTrigger umożliwia określenie Storyboard , które jest uruchamiane za każdym razem, gdy zdarzenie kierowane osiągnie element w jego trasie, który deklaruje EventTrigger dla tego zdarzenia. Zaletą EventTrigger ponad just obsługi zdarzenia i spowodowania uruchomienia istniejącej scenorysu jest to, że zapewnia lepszą kontrolę nad scenorysem EventTrigger i jego zachowaniem w czasie wykonywania. Aby uzyskać więcej informacji, zobacz Używanie wyzwalaczy zdarzeń do kontrolowania scenorysu po uruchomieniu.
Więcej informacji o zdarzeniach kierowanych
W tym temacie omówiono głównie zdarzenia kierowane z perspektywy opisywania podstawowych pojęć i oferowania wskazówek dotyczących sposobu i momentu reagowania na zdarzenia kierowane, które są już obecne w różnych elementach podstawowych i kontrolkach. Można jednak utworzyć własne zdarzenie kierowane w klasie niestandardowej wraz ze wszystkimi niezbędnymi obsługą, takimi jak wyspecjalizowane klasy danych zdarzeń i delegaty. Właściciel zdarzenia kierowanego może być dowolną klasą, ale zdarzenia kierowane muszą być wywoływane przez klasy i obsługiwane przez UIElement klasy lub ContentElement pochodne, aby były przydatne. Aby uzyskać więcej informacji na temat zdarzeń niestandardowych, zobacz Create a Custom Routed Event (Tworzenie niestandardowego zdarzenia trasowanego).
Zobacz też
.NET Desktop feedback