none
A FocusScope Nightmare (Bug?): Commands Are Disabled

    Question

  • I've got a simple menu with some simple commands:

     

    Code Snippet

    <Menu>

    <MenuItem Header="Edit">

    <MenuItem Command="ApplicationCommands.Cut" />

    <MenuItem Command="ApplicationCommands.Copy" />

    </MenuItem>

    </Menu>

     

     

    I've got a simple control:

     

    Code Snippet

    <UserControl x:Class="WpfApplication2.UserControlRed"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid />

    </UserControl>

     

     

    The code-behind for this control enables handling the 'Cut' command:

    Code Snippet

     

    public partial class UserControlRed : UserControl

    {

    public UserControlRed()

    {

    InitializeComponent();

    this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Cut, this.OnCut, this.OnAlwaysExecute));

    }

    public void OnCut(object sender, RoutedEventArgs routedEventArgs)

    {

    Console.WriteLine("Cut");

    }

    private void OnAlwaysExecute(object sender, CanExecuteRoutedEventArgs e)

    {

    e.CanExecute = true;

    }

    }

     

     

    This control is added to a simple page so it can be navigated to using a Frame:

     

    Code Snippet

    <!-- The Menu Commands are enabed with this code. -->

    <Page x:Class="WpfApplication2.PageRed"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:src="clr-namespace:WpfApplication2"

    Title="PageRed">

    <src:UserControlRed />

    </Page>

     

     

    Here's the nightmare: Adding a FocusScope to this page disables the menu items in the main window.

     

    Code Snippet

    <!-- The Menu Commands are disabled with this code. -->

    <Page x:Class="WpfApplication2.PageRed"

    FocusManager.IsFocusScope="true"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:src="clr-namespace:WpfApplication2"

    Title="PageRed">

    <src:UserControlRed />

    </Page>

     

     

    I've read every bit of documentation I could find on the subject.  It says that the command manager will route the command to the user interface element with the keyboard focus.  I've verified that the keyboard focus is on the desired element, yet the commands are still disabled.  I've also read some blogs where the author suggests that elements within the same FocusScope won't exchange commands, but I don't see how that restriction applies to this example.  The entire source code for this small project can be found here:

     

    ftp://www.markthreesoftware.com/Samples/

     

    Is this a bug or is there some undocumented feature of the FocusManager?

     

     

     

    Thursday, April 24, 2008 2:10 AM

All replies

  • I've got a simple menu with some simple commands:

     

    Code Snippet

    <Menu Focusable="False" >

    <MenuItem Header="Edit">

    <MenuItem Command="ApplicationCommands.Cut" />

    <MenuItem Command="ApplicationCommands.Copy" />

    </< FONT>MenuItem>

    </< FONT>Menu>

     

     

    I've got a simple control:

     

    Code Snippet

    <UserControl x:Class="WpfApplication2.UserControlRed"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Focusable="True">

    <Grid Focusable="True"/>

    </< FONT>UserControl>

     

     

    The code-behind for this control enables handling the 'Cut' command:

    Code Snippet

     

    public partial class UserControlRed : UserControl

    {

    public UserControlRed()

    {

    InitializeComponent();

    this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Cut, this.OnCut, this.OnAlwaysExecute));

    }

    public void OnCut(object sender, RoutedEventArgs routedEventArgs)

    {

    Console.WriteLine("Cut");

    }

    private void OnAlwaysExecute(object sender, CanExecuteRoutedEventArgs e)

    {

    e.CanExecute = true;

    }

    }

     

     

    This control is added to a simple page so it can be navigated to using a Frame:

     

    Code Snippet

    <!-- The Menu Commands are enabed with this code. -->

    <Page x:Class="WpfApplication2.PageRed"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:src="clr-namespace:WpfApplication2"

    Title="PageRed">

    <src:UserControlRed />

    </< FONT>Page>

     

     

    Here's the nightmare: Adding a FocusScope to this page disables the menu items in the main window.

     

    Code Snippet

    <!-- The Menu Commands are disabled with this code. -->

    <Page x:Class="WpfApplication2.PageRed"

    FocusManager.IsFocusScope="true"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:src="clr-namespace:WpfApplication2"

    Title="PageRed">

    <src:UserControlRed />

    </Page>

     

     

    I've read every bit of documentation I could find on the subject.  It says that the command manager will route the command to the user interface element with the keyboard focus.  I've verified that the keyboard focus is on the desired element, yet the commands are still disabled.  The entire source code for this small project can be found here:

     

    ftp://www.markthreesoftware.com/Samples/

     

    Is this a bug or is there some aspect of the FocusManager that has escaped me?

     

     

     

    Thursday, April 24, 2008 2:09 AM
  • What's happening here is definitely confusing, but isn't a bug.  Since the blue page is a FocusScope, yes it will keep track of what the last focused element was (except that in your code, you're creating a new one every time, so you can't really see that effect.)

     

    However, you are beset by two problems.  First, Windows and Menus are also FocusScopes.  Secondly, even if you were to disable this attribute of Window / Menu (not sure you can), clicking anywhere outside of an element with IsFocusScope=True (such as PageBlue.xaml) causes it to 1) lose keyboard focus then 2) persist it's logically focused element.  Think of the Page with IsFocusScope as an entirely separate window with it's own element, that goes dormant when you dont have it in the foreground.

     

    What happens when you click on your menu item is that you have a menu containing only text-related commands, and at that instant, no keyboard focus and selection on a textual element.  To see that this isnt caused by PageBlue, you can add a textbox to WindowMain.xaml, type some text in it, select that text (since cut and copy require both a text-input element with keyboard focus AND selected text) and then try your menu items again.

     

    I suggest that your restrict the use of IsFocusScope within your page to subelements that aren't textual (or not at all), so that if you need to handle routed commands from a higher level control for text commands, they will work.  It's a useful feature but not really one that you need for what you're doing with this sample app.

     

    Hope this helps,
    Matt

    Thursday, April 24, 2008 5:28 PM
    Moderator
  • Matt,

     

    #1)  I have a command handler installed in the control in the page to handle the 'Cut' or 'Copy' operation.  If you remove the 'FocusScope' from the page you will see them work property (that is, they'll write 'Cut' or 'Paste' to the output screen and the respective menu items are enabled).

     

    #2)  If I understand you correctly, your description of the FocusManager functions would render the whole CommandManager architecture pretty useless (and that may be the case, I'm still trying to figure this out).  If Menus route commands to the element with the keyboard focus, and the menus require the keyboard focus to select a menu item, then where do all the commands go?  That's right, to the menu.  There must be a mechanism that allows the menus to route to the 'keyboard focus' window even when they have the keyboard focus.

     

    #3) You get the same bug (feature) if you set the 'Focusable' attribute to false on the main menu.  This prevents the Blue or Red page from losing the focus.  I set the background color to bright blue when the keyboard focus is within the page so you can track who has the keyboard focus.

     

    #4)  I know I can get the commands to work when I'm outside of a FocusScope (as per your suggestion to put an edit box in the main window).  What I can't figure out, nor can I find any documentation to explain, why can't I direct a command to handlers inside a focus scope?  The example I posted was the minimum I could work out to demonstrate the problem.  I just put a more illustrative example back up on the FTP site:

     

    ftp://www.markthreesoftware.com/Samples/

     

    This one periodically dumps the description of the element with the input focus to the output window so you can see exactly how the keyboard focus is configured.

     

    Thursday, April 24, 2008 6:36 PM
  • Hi Donald,

    The link you provided above is not working for me, could you please directly send the source to me at v-mazho at microsoft dot com?

    Thanks
    Monday, April 28, 2008 2:27 AM
  • Marco,

    Here's a simple but dramatic facet of the FocusScope problem:

     

    Code Snippet

    <Window Height="300"
            Title="Keyboard Demo"
            Width="300"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid Name="mainGrid">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="60" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <ListView SelectionMode="Single">
                <ListViewItem>Blue</ListViewItem>
                <ListViewItem>Red</ListViewItem>
                <ListViewItem>None</ListViewItem>
            </ListView>
          <!-- Remove the 'IsFocusScope' from this line and the Check Box works properly but the logical focus doesn't persist. -->
          <StackPanel Background="LightGray"
                      FocusManager.IsFocusScope="True"
                      Focusable="True"
                      Grid.Column="1">
                <TextBox Width="130">Text Box</TextBox>
                <CheckBox Foreground="White" HorizontalAlignment="Center">Check Box</CheckBox>
         </StackPanel>
        </Grid>
    </Window>

     

     

     

    #1) Tab to the CheckBox.  Press the space bar.  The focus jumps to the ListView.

    #2) Tab back to the stack panel and notice that the selected item was persistent as you would expect from a FocusScope.

    #3) Remove the FocusScope and try the CheckBox again.

    #4) The CheckBox now works, but the selected item in the StackPanel doesn't persist.

     

    Monday, April 28, 2008 2:33 PM
  • Struggling with this myself. I've been through the documentation backward and forward, and I still don't get it.

     

    An important clue though. I think your lack of command routing is due to this:

     

    <Menu Focusable="False" >

     

    Command-routing seems to fail catastrophically when it can't assign keyboard focus in the menu/toolbar focus scope.

     

    I seem to be stuck between a rock and a hard place. Either I allow focus on my menus and toolbars, and lose focus in the main document; or I prevent focus on my menus and toolbars, and menus fail catastrophically. Button commands seem to route properly whether they are Focusable or not.

     

    Some explanation of how menus and/or tool bars restore focus to the oriignal focus scope would be really helpful. Whatever that mechanism is, it doesn't seem to work reliably. Knowing what it's supposed to be would allow me to either figure out why I've broken the as-designed mechanism, or give some thought as to how to re-implment the as-designed mechanism.

     

    What I'd really like is that my main document window (everything other than toolbars and menu items) regains keyboard focus at the aprropriate place after a menu command or toolbar button is clicked. Honestly, I'm not sure if this is supposed to work, or not. My consistent experience is that toolbars steal focus from the rest of the window, and there's nothing that can be done about it; and that menus also (sometimes?) steal focus from the rest of the window.

     

    What also seems to me to be a bit of a mystery is this: in my pages, command routing runs from document root to the menu, and back. Allegedly, one can place "Copy/Cut/Paste" buttons in a separate focus scope, and get cut/copy/paste commands routed to UI controls in the main focus scope. According to the documentation, this just happens. But nothing about the actual mechanism is mentioned in the existing documentation. What's the mechanism for that? And why doesn't it work on my pages?

     

     

     

     

    Monday, April 28, 2008 8:48 PM
  • I've run into this problem myself. I want to use focus scopes to persist the location of the focus in various different containers, so when the user switches between visible containers their last focused control within the newly visible container is persisted. Focus scopes were designed for this and work perfectly. The trouble is, for some undocumented reason they completely break command bindings. If I have a toolbar with a Cut command and the focus is within a textbox in a sub-focus-scope of the window, the command is disabled when it should be enabled.

     

    I can explain about focus though. WPF menus do need to get the focus, but you have to understand the difference between logical focus and input focus. Only one control can have input focus, but multiple controls can have logical focus. This is explained pretty well by MSDN and is how Microsoft were able to re-implement menus, a Win32 concept that previously relied on intercepting keystrokes with a modal message pump because the main document never actually lost focus while in a menu loop.

     

    Monday, April 28, 2008 10:21 PM
  •  Donald Roy Airey wrote:

    #1) Tab to the CheckBox.  Press the space bar.  The focus jumps to the ListView.

    #2) Tab back to the stack panel and notice that the selected item was persistent as you would expect from a FocusScope.

    #3) Remove the FocusScope and try the CheckBox again.

    #4) The CheckBox now works, but the selected item in the StackPanel doesn't persist



    I am afraid that I still have no idea what type of problem you have with FocusScope, and the concept of keyboard focus and logical focus, could you please elaborate on what type of behaviour you consider to be correct, and which you think is abnormal?

    Thanks
    Tuesday, April 29, 2008 7:27 AM
  • Marco,

     

    #1) Tab (Do not use the mouse) to the Check Box.  Press the space bar.  The focus jumps to the ListView.  This is the broken part.  There is no reason the focus should move just by toggling a check box.

    #2) You should now be in the ListView.  Tab back to the stack panel and notice that the the check box is still selected.  This part is correct.  This is what a FocusScope should do.

    #3) Remove the FocusManager.IsFocusScope property from the stack panel and restart the application (F5 in XamlPad).  Tab (do not use the mouse) to the Check Box again.  Press the space bar.  The focus stays on the space bar.  This is the expected behavior for a toggle button.

    #4) Tab back to the ListView and tab back into the stack panel.  You'll notice that, as expected, the last selected item in the stack panel wasn't selected because we removed the FocusScope.

    #5) The FocusScope is broken.  There is no reason the focus should jump to another control when you press the space bar in #1.  You can either have a working toggle button, or a working FocusScope, but you can't have both.

    Tuesday, April 29, 2008 10:57 AM
  • Robin,

     

    I've been doing some research and experimenting.  The <Menu Focusable="False"> doesn't have anything to do with the problem.  I put that property in the menu to insure that my Blue and Red Page would retain the focus.  You can see that it does in the debug output.  I wanted to insure that my Blue Page would retain the keyboard focus when the commands were sent from the menu items.  But in the end, it had nothing to do with the problem one way or another.

     

    Here's what I've found.  The documentation as well as the whole Focus architecture are broken.  First, the documentation states that a command is routed to the window with the Keyboard Focus when the 'Command Target' isn't specifically given.  This is wrong.  It appears that commands are routed to the Logical Focus Element of the Main Application Window.  To make things even more confusing, the commands are not automatically routed through a FocusScope.  To make things even more confusing, nested FocusScopes modify the tunneling algorithm for routed commands: they don't route directly from the application main window to the logical focus element of the Main Application Window.  They appear to stop at every FocusScope in the path and ask for directions.  And finally, to make things even more confusing, some controls, like the ListView, defy these rules and seem to manage to set the logical focus on the main window even though they have a focus scope function, thus stealing the commands away from your intended target.

     

    You may find the following helpful.  Place the following handler on the control where you want a focus scope.  I've got a frame window attached to the main window in my example. 

     

    Code Snippet

    this.mainFrame.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(OnFrameGotKeyboardFocus);

     

    The handler looks something like this:

     

    Code Snippet

    ///

    /// Handles the change of the keyboard focus to the main frame window of the browser.

    ///

    private void OnFrameGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)

    {

    // The Frame window used to navigate between pages is a FocusScope and must take care of advising the application's

    // Main Window FocusScope when anything inside the Frame has changed the focus. This update is done recursively for

    // all nested FocusScopes so that commands can be routed properly to their destination. Without this recursive update,

    // the tunnelling algorithm gets lost at the first FocusScope it finds.

    if (e.NewFocus is DependencyObject)

    {

    DependencyObject dependencyObject = e.NewFocus as DependencyObject;

    DependencyObject focusScope = FocusManager.GetFocusScope(dependencyObject);

    while (focusScope != Application.Current.MainWindow)

    {

    focusScope = FocusManager.GetFocusScope(VisualTreeHelper.GetParent(focusScope));

    FocusManager.SetFocusedElement(focusScope, e.NewFocus);

    }

    }

    }

     

    I lost a week of my time on this issue, but the application finally seems to respond to the keyboard commands in a logical way.  Good luck.

    Tuesday, April 29, 2008 11:28 AM
  • I've played around quite a bit with this, and here's the conclusion I've come to:

     

    - IsFocusScope doesn't do what you think it does.

     

    I've tried various flavors and combinations of managing sub-FocusScopes,and the following result seems clear to me: proper Keyboard focus management and command routing occurs properly ONLY in the topmost focus scope. The only place where IsFocusScope should be set is on objects whose children take temporary focus. Management of focus in containers must be done by other means other than by setting IsFocusScope -- most likely by providing an alternate implementation that looks like IsFocusScope, that watches GotFocusScope events, and manages focus using its own set of attached properties, and calls FocusManager.SetFocusedElement ONLY on the topmost frame.

     

    A from-scratch focus management scheme for containers turns out to be very straightforward given that the basic mechanisms provided by FocusManager allows for dual focus kind of things.

     

    I tried the code in the previous post. It fails to maintain keyboard focus on children with FocusManager.IsFocusScope set to true.

     

    As far as I can tell, the documentation is totally misleading. The feature allows for management of focus scope between one main focus scope, and one or more elements with temporary focus (typically a menu, toolbar, dockbar, &c). Any attempt to use IsFocusScope to manage persistent focus (longer than a mouse-click or a menu command) seems to be either broken, or not within the actual scope of original development, despite what the documentation says.

     

    In response to the original poster's question: Setting IsFocusScope=true on the root element of a page seems to be a very bad idea. Don't do that. :-) I'm not sure what it does do; but whatever it does, it isn't very useful.

     

     

    Tuesday, April 29, 2008 5:49 PM
  • Robin,

     

    >> I tried the code in the previous post. It fails to maintain keyboard focus on children with FocusManager.IsFocusScope set to true.

     

    I'm using it successfully in this scenario.  You ask why one would want to set the 'IsFocusScope' on a Frame or Page: this is how a basic browser or explorer type application will work.  You have a navigator in on the left side of the application (a tree view or list view) and you host the pages on the right side in a frame.  As you tab out of the navigator into your selected page, you would expect the focus to be restored.  The example I posted on ftp://www.markthreesoftware.com/Samples shows a very simplified example of a browser-type program that tries to use the FocusManager.  It demonstrates in as few lines as possible that the command structure is broken when an IsFocusScope property is attached to a child of the application window.

     

    Don

    Tuesday, April 29, 2008 7:33 PM
  • I think I can explain this after digging into the framework source code.

     

    1. After clicking, the MenuBase and ButtonBase class will try to restore keyboard focus to previous focused element by calling Keyboard.Focus(null). This will set keyboard focus to top level main window. Since Window is a FocusScope, this will set focus to main window's FocusedElement. Normally we don't expect a click will change the focus, that's where the confusion come from. But this behavior makes sense:

    1) MenuBase works in a open-dismiss way. It should not have the focus after clicking. Actually I think they should not get focus at all, like in Win32 or Win forms. But this is another topic.

    2) Normally after clicking a button, we're not likely to click it again. So it's naturaly to restore the focus to previously focused element.

     

    2. The nested FocusScope. It's not actually that complex as we expected. Whenever an UIElement receives keyboard focus, it will find its DIRECT parent focus scope, and set this focus scope's FocusedElement to itself. Keyboard focus leaves the focus scope will do nothing.

     

    Consider the check box sample you provided:

    1) If you set IsFocusScope="true" on StackPanel, focus the check box will set StackPanel's FocusedElement to check box, and main window's FocusedElement remains unchanged - ListViewItem; After clicking the check box, because of Keyboard.Focus(null) called, the keyboard focus will set to previous ListViewItem.

    2) If you remove IsFocusScope="true" on StackPanel, focus the check box will set main window's FocusedElement to the check box. Keyboard.Focus(null) will set the focus back to the check box.

    If you want both IsFocusScope="true" and no keyboard focus change after clicking the check box, add the following code to your window class (of course you need to add x:Name="checkBox" in the XAML file):

    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)

    {

    base.OnGotKeyboardFocus(e);

    if (e.Source == checkBox)

    FocusManager.SetFocusedElement(this, checkBox);

    }

     

    Hope this helps,

    - Weifen

    Friday, May 23, 2008 3:41 AM
  • Weifen, thanks, that's very useful information.

    One thing I don't quite understand is that the "disabled commands" problem also shows up for any RoutedUICommand, including those you define yourself. I wrote a little test application where some buttons are hooked up to a custom command. This command is bound to a CanExecute callback that always return true. I still get the same problem (buttons are disabled) when setting the container to be a Focus Scope.

    I don't understand this because, for one, my own CanExecute callback is not called. WPF decides the command is not executable by itself, through some unknown logic that probably looks at the buttons and their logical trees. Also, even if I use "TAB" to get the focus to that container, the buttons still stay disabled. I can vaguely understand how using pre-built commands like "Cut" and "Paste" can lead to some "magic" happening behind the scenes (they need a few things before they are enabled... some selected text, focus on an input element, etc.). However, I don't see what WPF is doing when it's my own command. Anyone has an explanation?

    In the end I had to walk away from the RoutedCommands, and implement my own version of ICommand (which is better anyway when you're using MVC/MVP).
    Thursday, July 24, 2008 2:51 PM
  • Wow long discussion on this...  I had to figure some of this out early on, and I thought I chip in with what I discovered.  I found some errors in the documentation that I don't think have been corrected.

    Based on my testing the correct explanation of command routing when no target is set is:

    The element within the Windows focus scope that has logical focus will be used as the command target.

    Note that it's the windows focus scope not the active focus scope.  And it's logical focus not keyboard focus.

    When it comes to command routing FocusScopes remove any item you place them on and it's child elements from the command routing path. 

    So if you create a focus scope in your app and want a command to route in to it you will  have to set the command target manually.

    Or, you can not use FocusScopes other than for toolbars, menus etc and handle the container focus problem manually.

    The above is pretty much covered in the posts above, but I think this states it a little clearer.  If not... sorry for butting in.<g>

    HTH


    John Fenton
    Thursday, July 24, 2008 5:06 PM
  • Perhaps only a small solace: Someone from the responsible feature team assured me that the design flaws around focus scopes are well understood, and there will be a solution eventually. Until then, a workaround like Donald's seems appropriate for similar nested focus scope situations.


    This posting is provided "AS IS" with no warranties, and confers no rights.
    • Proposed as answer by Wodahs Friday, August 01, 2008 4:18 AM
    Friday, July 25, 2008 7:31 PM
  • Thanks Chango!
    That's good news... I hope there will be an adequately early CTP/beta so that we don't replace this problem by a new one.
    Friday, August 01, 2008 1:44 AM
  • I encountered a different situation that leads to the same effects described above - all my commands were being disabled. In this situation, I had an ItemsControl whose ItemsTemplate changed (with a conditional style) based on a binding to a property of an object that implemented INotifyPropertyChanged. The problem was that if an element inside the active ItemsTemplate had focus (in this case, a Hyperlink), when the property changed the binding would update and immediately cause a switch to the other ItemsTemplate. The item that had focus now no longer existed, and all my commands were suddenly disabled until I gave another control focus.

    I solved this issue by setting Focusable="false" on all the controls in each of the affected ItemsTemplates. This worked for me since I was just using Hyperlinks, but for controls that need to be focusable to operate properly, I have not yet found a solution.

    --Brandon Siegel
    Wednesday, November 19, 2008 9:37 PM
  • I encountered the same problem too. In my case I was using an ItemsTemplateSelector, which produces the same effect - the controls get created and destroyed and when a control with focus disappears from the visual tree everything is bogus until another control gets the focus. In my case I needed some control to be focusable (like, you know, a TextBox) so I had to detect the template change and take the focus from it. With this code:

    //Takes focus from whichever control had it. Workaround to avoid a bug in WPF related to Commands and Focus. 
    FrameworkElement focusScope = (FrameworkElement)FocusManager.GetFocusScope(this); 
    IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope); 
    if (MustTakeFocusFrom(focusedElement)) 
        FocusManager.SetFocusedElement(focusScope, null); 

    Friday, November 28, 2008 8:48 AM
  • I just ran into the same problem.  My entire main menu was disabled, even though its commands were correctly polling their CanExecute methods, and even though buttons and shortcut keys for the same commands continued to work!  I thought I'd go mad until I found this thread.  Sure enough, the focus happened to be on a control that could not receive keyboard input, and explicitly switching the focus to a ListView on the main window immediately revived the main menu.

    I never explicitly set the Focusable property on any control, by the way, and until I read this thread I had never even heard about FocusScopes.  To my mind, making arbitrary custom commands dependent on any kind of current focus, or on the default command target, is a critical design flaw that absolutely must be fixed.  Custom commands should *never* care about anything but what I return from CanExecute.  I can add my own tests for any desired focus or target conditions in this event handler, after all.

    Monday, December 08, 2008 6:34 PM
  • Weifen Luo said:

    I think I can explain this after digging into the framework source code.

     

    1. After clicking, the MenuBase and ButtonBase class will try to restore keyboard focus to previous focused element by calling Keyboard.Focus(null). This will set keyboard focus to top level main window. Since Window is a FocusScope, this will set focus to main window's FocusedElement. Normally we don't expect a click will change the focus, that's where the confusion come from. But this behavior makes sense:

    1) MenuBase works in a open-dismiss way. It should not have the focus after clicking. Actually I think they should not get focus at all, like in Win32 or Win forms. But this is another topic.

    2) Normally after clicking a button, we're not likely to click it again. So it's naturaly to restore the focus to previously focused element.

     

    2. The nested FocusScope. It's not actually that complex as we expected. Whenever an UIElement receives keyboard focus, it will find its DIRECT parent focus scope, and set this focus scope's FocusedElement to itself. Keyboard focus leaves the focus scope will do nothing.

     

    Consider the check box sample you provided:

    1) If you set IsFocusScope="true" on StackPanel, focus the check box will set StackPanel's FocusedElement to check box, and main window's FocusedElement remains unchanged - ListViewItem; After clicking the check box, because of Keyboard.Focus(null) called, the keyboard focus will set to previous ListViewItem.

    2) If you remove IsFocusScope="true" on StackPanel, focus the check box will set main window's FocusedElement to the check box. Keyboard.Focus(null) will set the focus back to the check box.

    If you want both IsFocusScope="true" and no keyboard focus change after clicking the check box, add the following code to your window class (of course you need to add x:Name="checkBox" in the XAML file):

    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)

    {

    base.OnGotKeyboardFocus(e);

    if (e.Source == checkBox)

    FocusManager.SetFocusedElement(this, checkBox);

    }

     

    Hope this helps,

    - Weifen



    After reading all these post, I am still kind of lost. Especially I need some solutions in my case at http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/753c2a0b-753f-43d3-afb3-01d4d3c93787 

    Anyone could give me a head-up?

    Thanks
    Hardy
    Sunday, February 08, 2009 3:28 AM
  • I know this thread is no longer active, but there are a lot of links to it from various blogs and articles, and it helped me solved my problem, so I wanted to post my solution here for the benefit of others.  It does not solve the command target issue, but it does allow ButtonBase-derived controls to operate as ordinary, FocusScope-abiding citizens of WPF.  Specifically my problem was that I created a focus-scope for an adorner, and wanted to hide the adorner when focus left that scope.  Any button I placed in the adorner, however, would instantly close it as soon as the mouse click was released, even before the click event was fired.

    The key, as Weifen Luo pointed out, is the call to Keyboard.Focus(null).  Buttons, if set to their default ClickMode of Release, capture the mouse on a down-click, and release the mouse capture on mouse-up.  In the OnLostMouseCapture event handler of ButtonBase, two actions are taken: IsPressed is set to false (technically cleared, but same effect), and the ill-fated call to Keyboard.Focus is made.  It's pretty simple, then, just to override it, like so:

     

    public class FocusScopedButton : Button
    {
     protected override void OnLostMouseCapture(System.Windows.Input.MouseEventArgs e)
     {
      IsPressed = false;
     }
    }

     

    This can be done similarly for CheckBox, ToggleButton, etc.  Unfortunately, if the underlying architecture of ButtonBase undergoes changes, we could lose out on something since we are not calling into the base implementation.  But it's the price we have to pay if we want to use buttons in FocusScopes that aren't toolbars or menus...

    Hope this helps someone!

    Tuesday, June 08, 2010 1:52 PM
  • I remembered this thread while reading about FocusScope in Matthew MacDonald's "Pro WPF in C# 2010", and only now I'm finally beginning to wrap my head around how this mechanism actually works.  I found some links that have good explanations and that I wanted to post here as a kind of central deposit:

    http://www.codeproject.com/KB/WPF/EnhancedFocusScope.aspx -- also shows how to create your own custom focus scope that remembers its local focus but does not interfere with WPF command routing

    http://pointlessly.blogspot.com/2007/11/wpf-routed-commands-and-focus-scope.html

    http://blogs.msdn.com/b/ebooth/archive/2006/08/31/732609.aspx

    Matthew MacDonald, "Pro WPF in C# 2010", Apress 2010, page 280f ("Controls with Built-in Commands")

    Chris Sells & Ian Griffiths, "Programming WPF" 2nd ed., O'Reilly 2007, page 134ff ("Command Routing")

    Tuesday, July 06, 2010 8:53 AM
  • And another thing that I wanted to clarify, both for myself and others:  There are (at least) two problems with FocusScope.

    1. You cannot use the FocusScope mechanism to locally remember the focused element in different containers within the same window because that screws with command routing. The CodeProject article above gives a workaround for this problem (i.e. build your own focus scope mechanism).

    2. Menu items or toolbar buttons are by default placed within a separate FocusScope (for the menu or toolbar respectively).  If any such items trigger routed commands, and they do not have a command target already set, then WPF always looks for a command target by searching the element that has keyboard focus within the containing window (i.e. the next higher-up focus scope).

    So WPF does NOT simply look up the command bindings of the containing window, as you'd intuitively expect, but rather always looks for a keyboard-focused element to set as the current command target!  Apparently the WPF team took the quickest route here to make built-in commands such as Copy/Cut/Paste work with windows that contain multiple text boxes or the like; unfortunately they broke every other command along the way.

    And here's why: if the focused element within the containing window cannot receive keyboard focus (say, it's a non-interactive image), then ALL menu items and toolbar buttons are disabled -- even if they don't require any command target to execute!  The CanExecute handler of such commands is simply ignored.

    Apparently the only workaround for problem #2 is to explicitly set the CommandTarget of any such menu items or toolbar buttons to the containing window (or some other control).  That's most conveniently accomplished in code, by looping through them during window initialization.  This way they always have a valid command target, and thus won't attempt to find a keyboard-focused element that may not exist, and thus won't disable themselves inadvertently.

    Tuesday, July 06, 2010 9:40 AM
  • I don't mean to sound impatient, but I posted this two years ago.  A year ago we got word that the MS engineers were keenly aware of the issue and working on a resolution.  I've got the latest .NET Framework 4.0 but still have no soap.  The moment you touch the 'SetFocusedElement' method on a child of the top-level window, the entire command routing goes out to lunch and never returns.

    What is the status of this case?  Do the MS engineers have an alternate to the 'FocusManager' class that will work without directing the routed commands into a black hole?

    Monday, August 30, 2010 7:04 PM
  • I'm seeing the same strange focus issue where checking a checkbox is causing focus to be lost and placed somewhere else. See my post on StackOverflow for more details.

    Strange Focus Behavior for Simple WPF ItemsControl

     

    Thursday, February 10, 2011 7:41 AM
  • I'm seeing the same strange focus issue where checking a checkbox is causing focus to be lost and placed somewhere else. See my post on StackOverflow for more details.

    Strange Focus Behavior for Simple WPF ItemsControl

     


    That's been explained in this thread, but a lot of people still don't seem to get it.  Your thread at StackOverflow produced a nice clean explanation of why you are seeing that problem.  If some one else happens across this thread, I recommend following that link. 

    Unfortunately the documentation on Focus is still poor and gives people the idea that Focus Scopes are for some other purpose than what they were actually designed for, i.e. tool bars and menus.


    John Fenton
    Wordmasters Direct Mail and Data Processing Services
    Friday, February 11, 2011 2:03 AM