{"id":176,"date":"2008-07-01T19:23:56","date_gmt":"2008-07-01T17:23:56","guid":{"rendered":"http:\/\/blog.m-ri.de\/?p=176"},"modified":"2008-06-28T18:43:23","modified_gmt":"2008-06-28T16:43:23","slug":"tipps-tricks-mfc-command-routing-in-komplexen-uis","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2008\/07\/01\/tipps-tricks-mfc-command-routing-in-komplexen-uis\/","title":{"rendered":"Tipps &#038; Tricks: MFC Command Routing in komplexen UIs"},"content":{"rendered":"<p>UIs werden immer komplexer. Und manche UI passt sicher nicht mehr in ein simples und einfaches Frame\/Document\/View Modell. Oft genug wird hier noch ein Tool-Window gedockt, dort noch ein Ausgabefenster und hier noch ein nicht modaler Dialog mit Status Infos.<\/p>\n<p>Bringt man nun in einem solchen Fenster Buttons oder Toolbars unter, dann w\u00fcnscht man sich in manchen F\u00e4llen, dass ein Command-Handler ausgel\u00f6st werden soll, der in einem anderen Objekt (z.B. dem aktiven View) liegt.<br \/>\nOder man m\u00f6chte, dass eben auch in solch einem Fenster ein Command-Handler ber\u00fccksichtigt wird.<br \/>\nDer Ansatz andere Fenster in das Command Routing einzubauen ist die Funktion <em>CCmdTarget::OnCmdMsg<\/em>. Diese Methode hat zwei Funktionen.<\/p>\n<ol>\n<li>Sie dient dazu, dass in Men\u00fcs (auch Kontextmen\u00fcs) und auch in Toolbars Men\u00fcpunkte und Buttons ein- und auszuschalten. (<em>ON_UPDATE_COMMAND<\/em> Handler)<\/li>\n<li>Sie leitet die eigentliche <em>WM_COMMAND<\/em> Nachricht zur Ausf\u00fchrung an den entsprechenden zust\u00e4ndigen Handler weiter. (<em>ON_COMMAND<\/em> Handler).<\/li>\n<\/ol>\n<p>Zum besseren Verst\u00e4ndnis des Command Routings das die MFC als Standard vorsieht empfehle ich als <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/xt2c310k.aspx\">Lekt\u00fcre TN021<\/a>. Um abenteuerliche Konstrukte und \u00fcble Verbiegungen der guten Vorgaben in der MFC zu vermeiden sollten die Grundlagen des Routings in Fleisch und Blut \u00fcbergegangen sein.<br \/>\nUnd dann ist es an sich nicht schwer, Anpassungen vorzunehmen, die es wirklich einfach machen auch andere Fenster in das eigene Routing aufzunehmen ohne die MFC zu verbiegen.<\/p>\n<p>Nun zum Eingemachten:<br \/>\nWill man also Handler in anderen assoziierten Fenstern nutzen, dann muss man diese Fenster in die eigene angepasste <em>OnCmdMsg <\/em>Routing Struktur einbauen. Der beste Punkt daf\u00fcr ist in vielen F\u00e4llen das hostende <em>CMainFrame<\/em>. Der Grund ist einfach: Das <em>CMainFrame <\/em>ist in 99% aller F\u00e4lle die erste Adresse, an die ein <em>WM_COMMAND <\/em>ausgeliefert wird.<\/p>\n<p>Eine entsprechende Funktion kann so aussehen:<\/p>\n<pre lang=\"cpp\" line=\"1\">BOOL CMainFrame::OnCmdMsg(UINT nID,int nCode,void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)\r\n{\r\n\u00a0\u00a0\u00a0 \/\/ Give a special window the first chance to handle the command\r\n\u00a0\u00a0\u00a0 if (m_pSomeWindow-&gt;GetSafeHwnd() &amp;&amp;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 m_pSomeWindow-&gt;IsWindowVisible() &amp;&amp;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 m_pSomeWindow-&gt;IsActiveInSomeWayOrHasFocus())\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (m_pSomeWindow-&gt;OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return TRUE;\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \/\/ Do the standard routing (View, Frame, Application)\r\n\u00a0\u00a0\u00a0 if (__super::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return TRUE;\r\n\r\n\u00a0\u00a0\u00a0 \/\/ If not handled up to this point just give another window a chance\r\n\u00a0\u00a0\u00a0 if (m_pSomeOtherWindow-&gt;GetSafeHwnd() &amp;&amp;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 m_pSomeOtherWindow-&gt;IsWindowVisible() &amp;&amp;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 m_pSomeOtherWindow-&gt;IsActiveInSomeWayOrHasFocus())\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (m_pSomeWindow-&gt;OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return TRUE;\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 \/\/ not handled\r\n\u00a0\u00a0\u00a0 return FALSE;\r\n}<\/pre>\n<p>Anmerkungen:<\/p>\n<ul>\n<li>Meistens ist es bei diesen F\u00e4llen wichtig, dass Routing nicht immer durchzuf\u00fchren. Z.B. nur dann, wenn das Fenster sichtbar ist, den Fokus hat oder \u00e4hnliches (siehe Beispielcode).<\/li>\n<li>Weiterhin ist es f\u00fcr Kontextmen\u00fcs wichtig als Parent-Fenster ein von CFrameWnd abgeleitetes Fenster zu verwenden. Geschieht dies nicht, dann wird <em>WM_INITMENUPOPUP <\/em>nicht behandelt, und die Men\u00fcpunkte werden nicht enabled bzw. disabled. Wird das obige Verfahren mit <em>OnCmdMsg <\/em>korrekt angewendet, kann man als Parent Fenster f\u00fcr Kontextmn\u00fcs immer <em>AfxGetMainWnd <\/em>verwenden.<\/li>\n<li>Toolbars funktionieren nur dann korrekt wenn hier der korrekte Owner gesetzt wird. Das geschieht mit <em>CToolBar::SetOwner<\/em>. Auch hier sollte das \u00e4u\u00dfere Frame Window die <em>WM_COMMAND <\/em>Nachrichten erhalten, die dann \u00fcber den normalen weiteren (angepassten) Weg geroutet werden.<\/li>\n<\/ul>\n<p>Siehe auch <a href=\"http:\/\/blog.m-ri.de\/index.php\/2007\/07\/19\/command-routing-der-mfc-bei-kontext-menues-mit-trackpopupmenu\/\">Command Routing der MFC bei Kontext Men\u00fcs mit TrackPopupMenu<\/a>\u00a0\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>UIs werden immer komplexer. Und manche UI passt sicher nicht mehr in ein simples und einfaches Frame\/Document\/View Modell. Oft genug wird hier noch ein Tool-Window gedockt, dort noch ein Ausgabefenster und hier noch ein nicht modaler Dialog mit Status Infos. Bringt man nun in einem solchen Fenster Buttons oder Toolbars unter, dann w\u00fcnscht man sich &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2008\/07\/01\/tipps-tricks-mfc-command-routing-in-komplexen-uis\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eTipps &#038; Tricks: MFC Command Routing in komplexen UIs\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[30,4,3],"tags":[370,73,352,37],"class_list":["post-176","post","type-post","status-publish","format-standard","hentry","category-c","category-mfc","category-programmieren","tag-c","tag-command-routing","tag-mfc","tag-vs-tippstricks"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/comments?post=176"}],"version-history":[{"count":0,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/176\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=176"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}