c# - Why is Keyboard.FocusedElement null when focus is inside WindowsFormsHost? It breaks WPF command routing -
i have custom routeduicommand mycommand
gets executed via icommand.execute. top window has binding handle it:
<window.commandbindings> <commandbinding command="local:mainwindow.mycommand" canexecute="canexecutecommmand" executed="commandexecuted"/> </window.commandbindings>
this handler command. have windowsformshost winforms' textbox
control inside (for demo purpose). when focus inside textbox
, mycommand
doesn't reach top window. when focus inside wpf's native textbox
, command handler gets invoked expected.
i've figured out this happening because keyboard.focusedelement null
when focus inside windowsformshost
. why null
in case, wpf bug or design feature? missing something?
i believe command should reaching top window, regardless of focus is (when it's handler in visual tree , focusmanager.isfocusscope set correctly). have related question that.
the project sources available here.
xaml:
<window x:class="wpfcommandtest.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:wpfcommandtest" xmlns:wf="clr-namespace:system.windows.forms;assembly=system.windows.forms" title="mainwindow" height="480" width="640" background="gray"> <window.commandbindings> <commandbinding command="local:mainwindow.mycommand" canexecute="canexecutecommmand" executed="commandexecuted"/> </window.commandbindings> <stackpanel margin="20,20,20,20"> <textbox name="textboxoutput" focusable="true" istabstop="true" height="150" text="wpf textbox
"/> <windowsformshost focusable="true" keyboardnavigation.istabstop="true" height="150"> <wf:textbox x:name="textboxwf" text="winforms textbox" /> </windowsformshost> <button focusmanager.isfocusscope="true" name="btntest" focusable="false" istabstop="false" content="test (icommand.execute)" click="btntest_click" width="200"/> <button focusmanager.isfocusscope="true" focusable="false" istabstop="false" content="test (command property)" command="local:mainwindow.mycommand" width="200"/> <button focusmanager.isfocusscope="true" name="btnclearfocus" focusable="false" istabstop="false" content="clear focus" click="btnclearfocus_click" width="200"/> </stackpanel> </window>
c#:
using system; using system.windows; using system.windows.input; namespace wpfcommandtest { public partial class mainwindow : window { public static readonly routeduicommand mycommand = new routeduicommand("mycommand", "mycommand", typeof(mainwindow)); const string null = "null"; public mainwindow() { initializecomponent(); this.loaded += (s, e) => textboxoutput.focus(); // set focus on textbox } void canexecutecommmand(object sender, canexecuteroutedeventargs e) { e.canexecute = true; } void commandexecuted(object sender, executedroutedeventargs e) { var routedcommand = e.command routedcommand; var commandname = routedcommand != null ? routedcommand.name : null; log("*** executed: {0} ***, {1}", commandname, formatfocus()); } void btntest_click(object sender, routedeventargs e) { log("btntest_click, {0}", formatfocus()); icommand command = mycommand; if (command.canexecute(null)) command.execute(null); } void btnclearfocus_click(object sender, routedeventargs e) { focusmanager.setfocusedelement(this, this); keyboard.clearfocus(); log("btnclearfocus_click, {0}", formatfocus()); } void log(string format, params object[] args) { textboxoutput.appendtext(string.format(format, args) + environment.newline); textboxoutput.caretindex = textboxoutput.text.length; textboxoutput.scrolltoend(); } string formattype(object obj) { return obj != null ? obj.gettype().name : null; } string formatfocus() { return string.format("focus: {0}, keyboard focus: {1}", formattype(focusmanager.getfocusedelement(this)), formattype(keyboard.focusedelement)); } } }
to complete interop form-wpf need this:
app.xaml.cs:
public partial class app : application { protected override void onstartup(startupeventargs e) { windowsformshost.enablewindowsformsinterop(); base.onstartup(e); } }
Comments
Post a Comment