{"id":55000104,"date":"2017-10-01T00:00:00","date_gmt":"2020-03-27T19:28:40","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=104"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Bubbling_und_Tunneling_Routed_Events","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Bubbling_und_Tunneling_Routed_Events\/","title":{"rendered":"Bubbling und Tunneling: Routed Events"},"content":{"rendered":"<p><b>Im Vergleich zu VBA, wo jedes Ereignis f&uuml;r das Steuer-element behandelt wurde, welches es auch ausgel&ouml;st hat, gibt es unter WPF einige Erweiterungen. Es gibt dort auch solche Ereignisse, aber in vielen F&auml;llen werden Ereignisse an &uuml;bergeordnete Elemente weitergeleitet. Das h&ouml;rt sich erstmal so an, als ob man es nicht unbedingt ben&ouml;tigt. Dennoch wollen wir das Prinzip anhand eines Beispiels erl&auml;utern, damit Sie mitunter auftretendes unerwartetes Verhalten von Code interpretieren k&ouml;nnen.<\/b><\/p>\n<p>Unter WPF sind Elemente verschachtelt, das hei&szlig;t, es gibt &uuml;bergeordnete und untergeordnete Elemente. Das <b>Window<\/b>-Element ist normalerweise das Hauptelement, welches dann ein <b>Grid <\/b>enth&auml;lt, in dem sich wiederum ein <b>Stackpanel <\/b>mit einer Schaltfl&auml;che befinden k&ouml;nnte:<\/p>\n<pre>&lt;Window x:Class=\"BubblingAndTunneling.MainWindow\" ... Title=\"MainWindow\" Height=\"350\" Width=\"525\"&gt;\r\n     &lt;Grid&gt;\r\n         &lt;StackPanel&gt;\r\n             &lt;Button x:Name=\"btn\" Content=\"Klick mich!\" ... Click=\"btn_Click\"&gt;&lt;\/Button&gt;\r\n         &lt;\/StackPanel&gt;\r\n     &lt;\/Grid&gt;\r\n&lt;\/Window&gt;<\/pre>\n<h2>Direkte Ereignisse\/Direct Events<\/h2>\n<p>Wenn der Benutzer nun auf die Schaltfl&auml;che namens <b>btn <\/b>klickt, wird das Ereignis <b>Click <\/b>ausgel&ouml;st, welches &uuml;blicherweise durch eine Ereignismethode etwa namens <b>btn_Click <\/b>implementiert wird:<\/p>\n<pre>private void btn_Click(object sender, RoutedEventArgs e) {\r\n     MessageBox.Show(\"Klick!\");\r\n}<\/pre>\n<p>Bei dem <b>Click<\/b>-Ereignis handelt es sich um ein direktes Ereignis. Dieses wird nur von dem Element ausgel&ouml;st, f&uuml;r das es implementiert wurde.<\/p>\n<h2>Tunneling Events<\/h2>\n<p>Bei Tunneling Events handelt es sich um alle Ereignisse, die mit dem Pr&auml;fix <b>Preview <\/b>beginnen, also beispielsweise <b>Preview-MouseDown<\/b>. Was ist die Besonderheit dieser Ereignisse Sie werden immer vom Element der obersten Ebene aus zu den unteren Ebenen abgearbeitet. Wenn Sie also das Ereignis <b>PreviewMouseDown <\/b>f&uuml;r alle vier Elemente des obigen Beispiels definieren, sieht das wie folgt aus:<\/p>\n<pre>&lt;Window x:Class=\"BubblingAndTunneling.MainWindow\" ... Title=\"MainWindow\" Height=\"350\" Width=\"525\" MouseDown=\"Window_MouseDown\" PreviewMouseDown=\"Window_PreviewMouseDown\"&gt;\r\n     &lt;Grid MouseDown=\"Grid_MouseDown\" PreviewMouseDown=\"Grid_PreviewMouseDown\" &gt;\r\n         &lt;StackPanel MouseDown=\"StackPanel_MouseDown\" PreviewMouseDown=\"StackPanel_PreviewMouseDown\"&gt;\r\n             &lt;Button x:Name=\"btn\" Content=\"Klick mich!\" ... MouseDown=\"btn_MouseDown\" \r\n                 PreviewMouseDown=\"btn_PreviewMouseDown\"&gt;&lt;\/Button&gt;\r\n         &lt;\/StackPanel&gt;\r\n     &lt;\/Grid&gt;\r\n&lt;\/Window&gt;<\/pre>\n<p>F&uuml;r diese Ereignisse hinterlegen wir die folgenden Methoden (f&uuml;r <b>Debug.WriteLine <\/b>m&uuml;ssen Sie den passenden Namespace mit <b>using System.Diagnostics <\/b>hinzuf&uuml;gen):<\/p>\n<pre>private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"Window_PreviewMouseDown\");\r\n}\r\nprivate void Window_MouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"Window_MouseDown\");\r\n}\r\nprivate void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"Grid_PreviewMouseDown\");\r\n}\r\nprivate void Grid_MouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"Grid_MouseDown\");                       \r\n} \r\nprivate void StackPanel_PreviewMouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"StackPanel_PreviewMouseDown\");\r\n}\r\nprivate void StackPanel_MouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"StackPanel_MouseDown\");\r\n}\r\nprivate void btn_PreviewMouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"btn_PreviewMouseDown\");\r\n}\r\nprivate void btn_MouseDown(object sender, MouseButtonEventArgs e) {\r\n     Debug.WriteLine(\"btn_MouseDown\");\r\n}<\/pre>\n<p>Wenn wir nun die Anwendung starten und mit der linken Maustaste auf die Schaltfl&auml;che klicken, erhalten wir das Ergebnis aus Bild 1. Es werden also offensichtlich nur die Tunneling-Methoden ausgel&ouml;st, also diejenigen, die mit <b>Preview&#8230; <\/b>beginnen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_05\/pic_104_001.png\" alt=\"Es feuert nur die H&auml;lfte der angegebenen Ereignisse.\" width=\"499,6607\" height=\"327,2426\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Es feuert nur die H&auml;lfte der angegebenen Ereignisse.<\/span><\/b><\/p>\n<p>Immerhin ist hier gut zu erkennen, dass dies ausgehend von der obersten Ebene (<b>Window<\/b>) bis runter zum <b>Button<\/b>-Element geschieht. Aber warum werden die <b>MouseDown<\/b>-Ereignisse nicht ausgel&ouml;st<\/p>\n<p>Dies ist wiederum der Fall, wenn wir auf den freien Bereich neben der Schaltfl&auml;che klicken. Dann erhalten wir die folgende Ausgabe:<\/p>\n<pre>Window_PreviewMouseDown\r\nGrid_PreviewMouseDown\r\nStackPanel_PreviewMouseDown\r\nStackPanel_MouseDown\r\nGrid_MouseDown\r\nWindow_MouseDown<\/pre>\n<p>Hier werden also korrekt erst die Tunneling-Ereignisse ausgel&ouml;st und dann in umgekehrte Reihenfolge die Bubbling-Ereignisse.<\/p>\n<h2>Bubbling Events<\/h2>\n<p>Bevor wir uns darum k&uuml;mmern, warum beim Anklicken der Schaltfl&auml;che nur die Tunneling-Events ausgel&ouml;st werden, noch kurz die Erl&auml;uterung der Bubbling-Ereignisse. Dies sind die Ereignisse, die in umgekehrter Reihenfolge wie die Tunneling-Ereignisse ausgel&ouml;st werden &#8211; also ausgehend vom ausl&ouml;senden Element bis hin zum obersten Element der Hierarchie (wie gut im Beispiel oben zu sehen, wo wir nicht die Schaltfl&auml;che, sondern das <b>StackPanel<\/b>-Element angeklickt haben). Diese werden allerdings immer nach den Tunneling-Ereignissen abgearbeitet.<\/p>\n<h2>Warum kein MouseDown<\/h2>\n<p>Nun schauen wir uns an, warum die Bubbling Events nicht ausgef&uuml;hrt werden, wenn wir das <b>Button<\/b>-Element mit der linken Maustaste anklicken. Der Grund ist einfach: Wenn Sie mit der linken Maustaste auf einen Button klicken, wird dessen <b>Click<\/b>-Ereignis ausgel&ouml;st, was daf&uuml;r sorgt, dass das <b>MouseDown<\/b>-Ereignis nicht mehr feuert &#8211; und somit auch nicht die <b>MouseDown<\/b>-Ereignisse der in der Hierarchie &uuml;ber dem <b>Button<\/b>-Element liegenden Elemente. Dies gilt beispielsweise auch f&uuml;r das Textfeld. <\/p>\n<div class=\"rcp_restricted\"><p><span style=\"color: #ff0000;\">M&ouml;chten Sie weiterlesen? Dann l&ouml;sen Sie Ihr Ticket!<\/span><br \/>\n<span style=\"color: #ff0000;\">Hier geht es zur Bestellung des Jahresabonnements des Magazins <strong>Visual Basic Entwickler<\/strong>:<\/span><br \/>\n<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/shop.minhorst.com\/magazine\/363\/visual-basic-entwickler-jahresabonnement?c=77\">Zur Bestellung ...<\/a><\/span><br \/>\n<span style=\"color: #ff0000;\">Danach greifen Sie sofort auf <strong>alle rund 200 Artikel<\/strong> unseres Angebots zu - auch auf diesen hier!<\/span><br \/>\n<span style=\"color: #000000;\">Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:<\/span><\/p>\n<\/div>\n\n\t\n\t<form id=\"rcp_login_form\"  class=\"rcp_form\" method=\"POST\" action=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000104\/\">\n\n\t\t\n\t\t<fieldset class=\"rcp_login_data\">\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_login\">Username or Email<\/label>\n\t\t\t\t<input name=\"rcp_user_login\" id=\"rcp_user_login\" class=\"required\" type=\"text\"\/>\n\t\t\t<\/p>\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_pass\">Password<\/label>\n\t\t\t\t<input name=\"rcp_user_pass\" id=\"rcp_user_pass\" class=\"required\" type=\"password\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t\t<p>\n\t\t\t\t<input type=\"checkbox\" name=\"rcp_user_remember\" id=\"rcp_user_remember\" value=\"1\"\/>\n\t\t\t\t<label for=\"rcp_user_remember\">Remember me<\/label>\n\t\t\t<\/p>\n\t\t\t<p class=\"rcp_lost_password\"><a href=\"\/data\/wp\/v2\/posts\/55000104?rcp_action=lostpassword\"><\/a><\/p>\n\t\t\t<p>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_action\" value=\"login\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_redirect\" value=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000104\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"122f66fc6a\"\/>\n\t\t\t\t<input id=\"rcp_login_submit\" class=\"rcp-button\" type=\"submit\" value=\"Login\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t<\/fieldset>\n\n\t\t\n\t<\/form>\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Vergleich zu VBA, wo jedes Ereignis f&uuml;r das Steuer-element behandelt wurde, welches es auch ausgel&ouml;st hat, gibt es unter WPF einige Erweiterungen. Es gibt dort auch solche Ereignisse, aber in vielen F&auml;llen werden Ereignisse an &uuml;bergeordnete Elemente weitergeleitet. Das h&ouml;rt sich erstmal so an, als ob man es nicht unbedingt ben&ouml;tigt. Dennoch wollen wir das Prinzip anhand eines Beispiels erl&auml;utern, damit Sie mitunter auftretendes unerwartetes Verhalten von Code interpretieren k&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662017,66052017,44000001,44000027],"tags":[],"yst_prominent_words":[],"class_list":["post-55000104","post","type-post","status-publish","format-standard","hentry","category-662017","category-66052017","category-CGrundlagen","category-Excel_programmieren"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000104","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000104"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000104\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000104"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000104"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000104"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000104"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}