Freigeben über


Markieren von gerouteten Ereignissen als behandelt und Bearbeitung durch Klassen

Handler für ein routingfähiges Ereignis können das in den Ereignisdaten behandelte Ereignis markieren. Die Behandlung des Ereignisses wird die Route effektiv verkürzen. Die Klassenbehandlung ist ein Programmierkonzept, das von Routingereignissen unterstützt wird. Ein Klassenhandler hat die Möglichkeit, ein bestimmtes routingfähiges Ereignis auf Klassenebene mit einem Handler zu behandeln, der vor einem Instanzhandler für jede Instanz der Klasse aufgerufen wird.

Voraussetzungen

Dieses Thema befasst sich mit Konzepten, die in der Routed Events Overvieweingeführt wurden.

Wann Ereignisse als bearbeitet markiert werden sollten

Wenn Sie den Wert der Handled-Eigenschaft auf true in den Ereignisdaten für ein routingfähiges Ereignis festlegen, wird dies als "Markieren des behandelten Ereignisses" bezeichnet. Es gibt keine absolute Regel, wenn Sie Routingereignisse als behandelt markieren sollten, entweder als Anwendungsautor oder als Steuerelementautor, der auf vorhandene Routingereignisse reagiert oder neue Routingereignisse implementiert. Für den größten Teil sollte das Konzept des „Bearbeitet“-Status, wie es in den Ereignisdaten eines Routingereignisses dargestellt wird, als begrenztes Protokoll für die Reaktionen Ihrer Anwendung auf die verschiedenen in WPF-APIs bereitgestellten Routingereignisse sowie für benutzerdefinierte Routingereignisse verwendet werden. Eine weitere Möglichkeit, das Problem "behandelt" zu betrachten, besteht darin, dass Sie im Allgemeinen ein routiertes Ereignis als behandelt markieren sollten, wenn Ihr Code auf das Ereignis in einer bedeutenden und weitgehend vollständigen Weise reagiert hat. In der Regel sollte es nicht mehr als eine bedeutende Reaktion geben, die separate Handlerimplementierungen für ein einzelnes geroutetes Ereignis erfordert. Wenn mehr Antworten erforderlich sind, sollte der erforderliche Code über Anwendungslogik implementiert werden, die innerhalb eines einzelnen Handlers verkettet ist, anstatt das Routed-Event-System für die Weiterleitung zu verwenden. Das Konzept, was "signifikant" ist, ist auch subjektiv, und hängt von Ihrer Anwendung oder Ihrem Code ab. Als allgemeine Richtlinie sind einige Beispiele für eine "wesentliche Reaktion" enthalten: Festlegen des Fokus, Ändern des öffentlichen Status, Festlegen von Eigenschaften, die die visuelle Darstellung beeinflussen, und Auslösen anderer neuer Ereignisse. Beispiele für nicht signifikante Antworten sind: Ändern des privaten Zustands (ohne visuelle Auswirkung oder programmgesteuerte Darstellung), Protokollierung von Ereignissen oder Betrachten der Argumente eines Ereignisses und die Entscheidung, nicht darauf zu reagieren.

Das Verhalten des Routing-Ereignissystems verstärkt dieses Modell der signifikanten Reaktion für die Verwendung des behandelten Zustands eines Routingereignisses, da Handler, die in XAML hinzugefügt wurden, oder die allgemeine Signatur von AddHandler nicht als Reaktion auf ein geroutetes Ereignis aufgerufen werden, bei dem die Ereignisdaten bereits als behandelt gekennzeichnet sind. Sie müssen den zusätzlichen Aufwand in Kauf nehmen, um einen Handler mit der handledEventsToo-Parameterversion (AddHandler(RoutedEvent, Delegate, Boolean)) hinzuzufügen, um geroutete Ereignisse zu behandeln, die von früheren Teilnehmern in der Ereignisübertragung als behandelt markiert wurden.

Unter bestimmten Umständen kennzeichnen Steuerelemente bestimmte geroutete Ereignisse als behandelt. Ein behandeltes Routingereignis stellt eine Entscheidung von WPF-Steuerelementautoren dar, dass die Aktionen des Steuerelements als Reaktion auf das Routingereignis als Teil der Steuerelementimplementierung erheblich oder vollständig sind und das Ereignis keine weitere Behandlung benötigt. Dies geschieht in der Regel durch das Hinzufügen eines Klassenhandlers für ein Ereignis oder durch das Überschreiben eines der virtuellen Klassenhandler, die in einer Basisklasse vorhanden sind. Sie können diese Ereignisbehandlung bei Bedarf weiterhin umgehen. Weitere Informationen finden Sie im Abschnitt Umgehen der Unterdrückung von Ereignissen durch Steuerelemente weiter unten in diesem Thema.

Vorschauereignisse (Tunneling) vs. Bubbling-Ereignisse und Ereignisbehandlung

Die Routing-Ereignisvorschau sind Ereignisse, die einer Tunnelroute durch die Elementstruktur folgen. Die in der Benennungskonvention ausgedrückte "Vorschau" ist ein Hinweis auf das allgemeine Prinzip für Eingabeereignisse, bei denen Preview- (Tunneling-) Routingereignisse vor den entsprechenden Bubbling-Routingereignissen ausgelöst werden. Darüber hinaus haben Eingaberoutenereignisse mit einem Tunneling- und Bubbling-Paar eine eindeutige Verarbeitungslogik. Wenn das Tunneling-/Vorschau-Routingereignis von einem Listener als verarbeitet markiert wird, wird das Bubbling-Routingereignis ebenfalls als verarbeitet markiert, noch bevor Listener des Bubbling-Routingereignisses es empfangen. Die Tunnel- und Bubbling-Routingereignisse sind technisch getrennte Ereignisse, sie teilen jedoch absichtlich dieselbe Instanz von Ereignisdaten, um dieses Verhalten zu ermöglichen.

Die Verbindung zwischen den Tunneling- und Bubbling-Routingereignissen wird durch die interne Implementierung erreicht, indem jede gegebene WPF-Klasse ihre eigenen deklarierten Routingereignisse auslöst, und dies gilt für die gekoppelten Eingabe-Routingereignisse. Wenn diese Implementierung auf Klassenebene jedoch nicht vorhanden ist, besteht keine Verbindung zwischen einem Tunneling-Routingereignis und einem Bubbling-Routingereignis, die dasselbe Benennungsschema verwenden: Ohne eine solche Implementierung wären sie zwei vollständig getrennte Routingereignisse und würden nicht in Sequenz ausgelöst oder Ereignisdaten gemeinsam nutzen.

Weitere Informationen zum Implementieren von Tunnel-/Blaseneingabe-Routingereignispaaren in einer benutzerdefinierten Klasse finden Sie unter Erstellen eines benutzerdefinierten Routingereignisses.

Klassenhandler und Instanzhandler

Routingereignisse berücksichtigen zwei verschiedene Listenertypen für das Ereignis: Klassenlistener und Instanzlistener. Klassenlistener sind vorhanden, da Typen eine bestimmte EventManager-API ,RegisterClassHandler, in ihrem statischen Konstruktor aufgerufen oder eine virtuelle Klassenhandlermethode aus einer Elementbasisklasse überschrieben haben. Instanzlistener sind bestimmte Klasseninstanzen/Elemente, bei denen mindestens ein Handler für dieses Routingereignis durch einen Aufruf von AddHandlerangefügt wurde. Vorhandene WPF-Routingereignisse führen Aufrufe an AddHandler als Teil des CLR-Ereigniswrappers (Common Language Runtime) durch, fügen{} hinzu und entfernen{} Implementierungen des Ereignisses, wodurch auch der einfache XAML-Mechanismus zum Anfügen von Ereignishandlern über eine Attributsyntax aktiviert wird. Daher entspricht auch die einfache XAML-Verwendung letztendlich einem AddHandler Aufruf.

Elemente im visuellen Baum werden auf registrierte Handler-Implementierungen überprüft. Handler werden möglicherweise während der gesamten Route aufgerufen, in der Reihenfolge, die dem Typ der Routingstrategie für dieses Routingereignis inhärent ist. Beispielsweise rufen Bubblingroutenereignisse zuerst die Handler auf, die mit demselben Element verbunden sind, das das Routingereignis ausgelöst hat. Anschließend "blubbert" das routingfähige Ereignis zum nächsten übergeordneten Element weiter, bis das Anwendungsstammelement erreicht ist.

Aus Sicht des Stammelements in einer Bubblingroute, wenn die Klassenbehandlung oder ein Element näher an der Quelle des gerouteten Ereignisses Handler aufruft, die die Ereignisargumente als behandelt markieren, dann werden Handler für das Stammelement nicht aufgerufen, und die Ereignisroute wird wirksam verkürzt, bevor das Stammelement erreicht wird. Die Route wird jedoch nicht vollständig angehalten, da Handler mithilfe einer speziellen Bedingung hinzugefügt werden können, die weiterhin aufgerufen werden sollten, auch wenn ein Klassenhandler oder Instanzhandler das geroutete Ereignis als behandelt markiert hat. Dies wird in Hinzufügen von Instanzhandlern erläutert, die ausgelöst werden, auch wenn Ereignisse als behandeltgekennzeichnet sind, weiter unten in diesem Thema.

Auf einer tieferen Ebene als die Ereignisroute gibt es auch potenziell mehrere Klassenhandler, die auf einer bestimmten Instanz einer Klasse handeln. Dies liegt daran, dass das Klassenbehandlungsmodell für Routingereignisse alle möglichen Klassen in einer Klassenhierarchie ermöglicht, jeden eigenen Klassenhandler für jedes Routingereignis zu registrieren. Jeder Klassenhandler wird einem internen Speicher hinzugefügt, und wenn die Ereignisroute für eine Anwendung erstellt wird, werden alle Klassenhandler zur Ereignisroute hinzugefügt. Klassenhandler werden der Route hinzugefügt, sodass der am weitesten abgeleitete Klassenhandler zuerst aufgerufen wird und die Klassenhandler aus den jeweils übergeordneten Basisklassen anschließend abgerufen werden. Im Allgemeinen werden Klassenhandler nicht registriert, sodass sie auch auf Routingereignisse reagieren, die bereits als behandelt markiert wurden. Daher ermöglicht dieser Klassenbehandlungsmechanismus eine von zwei Optionen:

  • Abgeleitete Klassen können die Klassenbehandlung ergänzen, die von der Basisklasse geerbt wird, indem sie einen Handler hinzufügen, der das routbare Ereignis nicht als behandelt kennzeichnet, da der Handler der Basisklasse erst nach dem Handler der abgeleiteten Klasse aufgerufen wird.

  • Abgeleitete Klassen können die Klassenbehandlung der Basisklasse ersetzen, indem sie einen Klassenhandler hinzufügen, der das geroutete Ereignis als bearbeitet markiert. Sie sollten mit diesem Ansatz vorsichtig sein, da er potenziell das beabsichtigte Basisdesign der Steuerelemente in Bereichen wie der visuellen Darstellung, der Zustandslogik, der Eingabeverarbeitung und der Befehlsverarbeitung ändern könnte.

Klassenbehandlung von Routingereignissen nach Steuerelementbasisklassen

Auf jedem jeweiligen Elementknoten in einer Ereignisroute haben Klassenlistener die Möglichkeit, auf das geroutete Ereignis zu reagieren, bevor ein Instanzlistener für das Element kann. Aus diesem Grund werden Klassenhandler manchmal verwendet, um Routingereignisse zu unterdrücken, die von einer bestimmten Steuerelementklassenimplementierung nicht weiter weitergegeben werden sollen, oder um eine spezielle Behandlung dieses routingfähigen Ereignisses bereitzustellen, das ein Feature der Klasse ist. Beispielsweise kann eine Klasse ein eigenes klassenspezifisches Ereignis auslösen, das mehr Einzelheiten darüber enthält, was einige Benutzereingabebedingung im Kontext dieser bestimmten Klasse bedeutet. Die Klassenimplementierung kann dann das allgemeinere Routingereignis als behandelt markieren. Klassenhandler werden normalerweise so hinzugefügt, dass sie bei Routingereignissen, deren freigegebene Ereignisdaten bereits als bearbeitet markiert wurden, nicht aufgerufen werden. Für atypische Fälle gibt es jedoch auch eine RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean)-Signatur, die Klassenhandler registriert, um sie selbst dann aufzurufen, wenn Routingereignisse als bearbeitet markiert sind.

Class Handler Virtuals

Einige Elemente, insbesondere die Basiselemente wie UIElement, stellen leere virtuelle Methoden wie "On*Event" und "OnPreview*Event" bereit, die ihrer Liste der öffentlichen weitergereichten Ereignisse entsprechen. Diese virtuellen Methoden können überschrieben werden, um einen Klassenhandler für dieses Routingereignis zu implementieren. Die Basiselementklassen registrieren diese virtuellen Methoden als Klassenhandler für jedes solche Routingereignis mithilfe von RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) wie weiter oben beschrieben. Die virtuellen On*-Ereignismethoden vereinfachen die Implementierung der Klassenhandhabung für die relevanten gerouteten Ereignisse, ohne dass für jeden Typ spezielle Initialisierungen in statischen Konstruktoren erforderlich sind. Sie können beispielsweise die Klassenbehandlung für das DragEnter-Ereignis in jeder von UIElement abgeleiteten Klasse hinzufügen, indem Sie die virtuelle Methode OnDragEnter überschreiben. Innerhalb der Außerkraftsetzung können Sie das Routingereignis behandeln, andere Ereignisse auslösen, klassenspezifische Logik initiieren, die Elementeigenschaften für Instanzen oder eine beliebige Kombination dieser Aktionen ändern kann. In der Regel sollten Sie die Basisimplementierung in solchen Überschreibungen aufrufen, auch wenn Sie das Ereignis als verarbeitet kennzeichnen. Das Aufrufen der Basisimplementierung wird dringend empfohlen, da sich die virtuelle Methode auf der Basisklasse befindet. Das standardmäßig geschützte virtuelle Muster zum Aufrufen der Basisimplementierungen aus jedem virtuellen Muster ersetzt und parallelisiert einen ähnlichen Mechanismus, der bei der Behandlung von Routing-Ereignisklassen nativ ist. Dabei werden Klassenhandler für alle Klassen in einer Klassenhierarchie für jede Instanz aufgerufen, beginnend mit dem Handler der am weitesten abgeleiteten Klasse und bis hin zum Basisklassenhandler. Sie sollten den Basisimplementierungsaufruf nur auslassen, wenn Ihre Klasse eine absichtliche Anforderung zum Ändern der Basisklassenbehandlungslogik hat. Ob Sie die Basisimplementierung vor oder nach Ihrem überschreibenden Code aufrufen, hängt von der Art Ihrer Implementierung ab.

Verarbeitung von Eingabeereignisklassen

Die virtuellen Methoden des Klassenhandlers sind alle so registriert, dass sie nur in Fällen aufgerufen werden, in denen noch nicht als behandelt markierte gemeinsame Ereignisdaten vorliegen. Außerdem werden ausschließlich für die Eingabeereignisse die Tunnel- und Bubbling-Versionen typischerweise nacheinander ausgelöst und die Ereignisdaten gemeinsam genutzt. Dies bedeutet, dass es bei einem bestimmten Paar von Klassenhandlern für Eingabeereignisse, von denen der eine die Tunnelversion und der andere die Bubbling-Version ist, vorkommen kann, dass Sie das Ereignis nicht sofort als behandelt kennzeichnen möchten. Wenn Sie die virtuelle Methode für die Tunnelverarbeitungsklasse implementieren, um das behandelte Ereignis zu markieren, wird verhindert, dass der Bubbling-Klassenhandler aufgerufen wird (und verhindert, dass alle normalerweise registrierten Instanzhandler für das Tunneling- oder Bubbling-Ereignis aufgerufen werden).

Sobald die Behandlung von Klassen für einen Knoten abgeschlossen ist, werden die Instanz-Listener berücksichtigt.

Hinzufügen von Instanzhandlern, die ausgelöst werden, auch wenn Ereignisse als behandelt markiert werden

Die AddHandler-Methode bietet eine spezielle Überladung, mit der Sie Handler hinzufügen können. Diese werden vom Ereignissystem aufgerufen, sobald ein Ereignis das Behandlungselement in der Route erreicht, auch wenn ein anderer Handler die Ereignisdaten bereits angepasst hat, um das Ereignis als verarbeitet zu markieren. Dies geschieht in der Regel nicht. Im Allgemeinen können Handler geschrieben werden, um alle Bereiche des Anwendungscodes anzupassen, die von einem Ereignis beeinflusst werden könnten. Dies gilt unabhängig davon, wo das Ereignis in einem Elementbaum behandelt wurde, selbst wenn mehrere Endergebnisse gewünscht sind. Außerdem gibt es in der Regel nur ein Element, das auf dieses Ereignis reagieren muss, und die entsprechende Anwendungslogik wurde bereits ausgeführt. Die handledEventsToo-Überladung ist jedoch für die Ausnahmefälle verfügbar, in denen ein anderes Element in einer Elementstruktur oder der Steuerelementkomposition bereits ein Ereignis als behandelt markiert hat, andere Elemente in der Elementstruktur jedoch (je nach Route) weiterhin ihre eigenen Handler aufrufen möchten.

Wann behandelte Ereignisse als unbehandelt markiert werden sollen

Im Allgemeinen sollten geroutete Ereignisse, die als behandelt gekennzeichnet sind, nicht als unbehandelt gekennzeichnet werden (Handled zurückgesetzt auf false), auch nicht von Handlern, die auf handledEventsTooreagieren. Einige Eingabeereignisse haben jedoch Darstellungen auf höherer und niedrigerer Ebene, die sich überlappen können, wenn das Ereignis auf höherer Ebene an einer Position im Baum und das Ereignis auf niedrigerer Ebene an einer anderen Position vorkommt. Betrachten Sie beispielsweise den Fall, in dem ein untergeordnetes Element auf ein Tastenereignis auf hoher Ebene lauscht, z. B. TextInput, während ein übergeordnetes Element auf ein Tastenereignis auf niedriger Ebene lauscht, z. B. KeyDown. Wenn das übergeordnete Element das Ereignis auf niedriger Ebene verarbeitet, kann das Ereignis auf höherer Ebene auch im untergeordneten Element unterdrückt werden, obwohl es intuitiv die erste Gelegenheit zur Verarbeitung des Ereignisses haben sollte.

In diesen Situationen kann es erforderlich sein, Handler sowohl den übergeordneten als auch den untergeordneten Elementen für das Ereignis auf niedriger Ebene hinzuzufügen. Die Implementierung des untergeordneten Elementhandlers kann das Ereignis auf niedriger Ebene als behandelt markieren, aber die Implementierung des übergeordneten Elementhandlers würde es erneut als unbehandelt festlegen, damit weitere Elemente den Baum hinauf (sowie das Ereignis auf hoher Ebene) die Gelegenheit haben, zu reagieren. Diese Situation sollte ziemlich selten sein.

Absichtliches Unterdrücken von Eingabeereignissen beim Steuerungs-Compositing

Das Hauptszenario, in dem die Klassenbehandlung von Routingereignissen verwendet wird, ist für Eingabeereignisse und zusammengesetzte Steuerelemente vorgesehen. Ein zusammengesetztes Steuerelement besteht definitionsgemäß aus mehreren funktionalen Steuerelementen oder Steuerelementbasisklassen. Häufig möchte der Autor des Steuerelements alle möglichen Eingabeereignisse, die jede der Unterkomponenten auslösen kann, zusammenführen, um das gesamte Steuerelement als einzige Ereignisquelle darzustellen. In einigen Fällen besteht die Möglichkeit, dass der Autor des Steuerelements die Ereignisse von Komponenten vollständig unterdrückt oder durch ein komponentendefiniertes Ereignis ersetzt, das weitere Informationen enthält oder ein spezifischeres Verhalten impliziert. Das kanonische Beispiel, das für jeden Komponentenautor sofort sichtbar ist, ist, wie eine Windows Presentation Foundation (WPF) Button jedes Mausereignis behandelt, das schließlich in das intuitive Ereignis mündet, das alle Schaltflächen haben: ein Click-Ereignis.

Die Button-Basisklasse (ButtonBase) leitet sich von Control ab, die wiederum von FrameworkElement und UIElementabgeleitet ist, und ein Großteil der für die Verarbeitung von Eingaben erforderlichen Ereignisinfrastruktur ist auf der UIElement-Ebene verfügbar. Insbesondere verarbeitet UIElement allgemeine Mouse Ereignisse, die Treffertests für den Mauscursor innerhalb seiner Grenzen behandeln, und stellt unterschiedliche Ereignisse für die am häufigsten verwendeten Schaltflächenaktionen bereit, z. B. MouseLeftButtonDown. UIElement stellt außerdem eine leere virtuelle OnMouseLeftButtonDown als vorab registrierten Klassenhandler für MouseLeftButtonDownbereit, und ButtonBase überschreibt diese. Ebenso verwendet ButtonBase Klassenbehandler für MouseLeftButtonUp. Bei den Außerkraftsetzungen, bei denen die Ereignisdaten übergeben werden, kennzeichnen die Implementierungen die RoutedEventArgs-Instanz als behandelt, indem sie Handled auf truesetzen, und die gleichen Ereignisdaten werden entlang des restlichen Routings zu anderen Klassenhandlern sowie zu Instanzhandlern oder Ereignissettern weitergegeben. Außerdem wird die OnMouseLeftButtonUp-Überschreibung danach das Click-Ereignis auslösen. Das Endergebnis für die meisten Hörer wird sein, dass die Ereignisse MouseLeftButtonDown und MouseLeftButtonUp "verschwinden" und stattdessen durch Clickersetzt werden, ein Ereignis, das mehr Bedeutung innehat, weil bekannt ist, dass dieses Ereignis von einem echten Schaltknopf stammt und nicht von einem zusammengesetzten Teil des Knopfes oder einem anderen Element überhaupt.

Umgehen der Ereignisunterdrückung durch Steuerelemente

Manchmal kann dieses Ereignisunterdrückungsverhalten innerhalb einzelner Steuerelemente einige allgemeinere Absichten der Ereignisbehandlungslogik für Ihre Anwendung beeinträchtigen. Wenn Ihre Anwendung aus irgendeinem Grund einen Handler für MouseLeftButtonDown im Stammelement der Anwendung hatte, würden Sie feststellen, dass ein Mausklick auf eine Schaltfläche die Handler MouseLeftButtonDown oder MouseLeftButtonUp auf der Stammebene nicht aufruft. Das Ereignis selbst wurde tatsächlich weitergereicht (auch hier werden Ereignisrouten nicht wirklich beendet, aber das Ereignisroutensystem ändert sein Verhalten bei der Aufrufverarbeitung von Handlern, nachdem sie als verarbeitet markiert wurden). Wenn das geroutete Ereignis die Schaltfläche erreichte, markierte die Klassenbehandlung der ButtonBase die MouseLeftButtonDown als behandelt, da sie das Click Ereignis durch ein bedeutungsvolleres Ereignis ersetzen wollte. Daher würde kein Standard-MouseLeftButtonDown-Handler weiter oben in der Route aufgerufen. Es gibt zwei Techniken, mit denen Sie sicherstellen können, dass Ihre Handler in diesem Fall aufgerufen werden.

Die erste Technik besteht darin, den Handler absichtlich mithilfe der handledEventsToo-Signatur von AddHandler(RoutedEvent, Delegate, Boolean)hinzuzufügen. Eine Einschränkung dieses Ansatzes besteht darin, dass diese Technik zum Anfügen eines Ereignishandlers nur aus Code und nicht aus Markup möglich ist. Die einfache Syntax zum Angeben des Ereignishandlernamens als Ereignisattributewert über XAML (Extensible Application Markup Language) aktiviert dieses Verhalten nicht.

Die zweite Technik funktioniert nur für Eingabeereignisse, bei denen die Tunnel- und Bubbling-Versionen des Routingereignisses gekoppelt sind. Für diese Routingereignisse können Sie stattdessen Handler zum äquivalenten Routingereignis "Vorschau/Tunneling" hinzufügen. Dieses Routingereignis wird vom Stamm aus die Route durchtunneln, sodass der Code für die Verarbeitung von Schaltflächenklassen es nicht abfangen würde, vorausgesetzt, Sie haben den Preview-Handler auf einer übergeordneten Ebene des Elementbaums der Anwendung angefügt. Wenn Sie diesen Ansatz verwenden, sollten Sie vorsichtig sein, wenn Sie ein Vorschauereignis markieren, das behandelt wird. Wenn das Beispiel mit PreviewMouseLeftButtonDown am Wurzelelement behandelt wird und Sie das Ereignis in der Handler-Implementierung als Handled markieren, würden Sie tatsächlich das Click-Ereignis unterdrücken. Das ist in der Regel kein wünschenswertes Verhalten.

Siehe auch