#1,075 – Triggering on IsKeyboardFocusWithin Property

You can set up a trigger that fires whenever a control’s IsKeyboardFocused property becomes truechanging the value of some other property when the control gains keyboard focus.

You can also trigger on the IsKeyboardFocusWithin property.  This property will get set to true for an element when any child of that element has keyboard focus.

In the example below, we set the background color of either StackPanel when any element within the StackPanel has focus.  This technique may be useful when you want to keep track of what section of a window the user is working in and do something based on that knowledge.

    <Window.Resources>
        <Style x:Key="HoneydewFocus" TargetType="StackPanel">
            <Style.Triggers>
                <Trigger Property="IsKeyboardFocusWithin" Value="true">
                    <Setter Property="Background" Value="Honeydew"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <StackPanel>
        <StackPanel Orientation="Horizontal" Margin="10"
                    Style="{StaticResource HoneydewFocus}">
            <Button Content="Click Me" VerticalAlignment="Center"/>
            <TextBox Width="200" Height="25" Margin="10"/>
        </StackPanel>

        <StackPanel Orientation="Horizontal" Margin="10"
                    Style="{StaticResource HoneydewFocus}">
            <Button Content="Or Me" VerticalAlignment="Center"/>
            <TextBox Width="200" Height="25" Margin="10"/>
        </StackPanel>
    </StackPanel>

1075-001

1075-002

Advertisement

#847 – Default Button Behavior Depends on Focus

When you set the IsDefault property of a Button to true, the user can activate the button by pressing the ENTER key.

The default behavior of a Button, however, will depend on which control in the window has focus when the user presses ENTER.  If the control that has focus can itself handle the ENTER key, that control will activate when ENTER is pressed, rather than a Button that has IsDefault set to true.

In the example below, the second TextBox has AcceptsReturn set to true and the “Save” button has IsDefault set to true.  Because both the second TextBox and the Cancel button can themselves handle the ENTER key, the “Save” button will only activate on ENTER if the first TextBox has focus when ENTER is pressed.

847-001

847-002

#643 – Disabled Controls Cannot Get Focus

When a control is disabled, i.e. its IsEnabled property is set to false, the user cannot give the control keyboard focus by clicking on it.  The control also cannot gain focus by use of the tab key.  Disabled controls cannot get focus, even if both their Focusable and IsTabStop properties are set to true.

    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBox Text="IsEnabled=true" IsEnabled="True" Width="140" Margin="10"/>
            <TextBox Text="IsEnabled=false" IsEnabled="False" Width="140" Margin="10"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Button Content="IsEnabled=true" IsEnabled="True" Margin="10"/>
            <Button Content="IsEnabled=false" IsEnabled="False" Margin="10"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <ComboBox IsEnabled="True" Margin="10" SelectedIndex="0">
                <ComboBoxItem Content="McClellan"/>
                <ComboBoxItem Content="Hooker"/>
                <ComboBoxItem Content="Meade"/>
            </ComboBox>
            <ComboBox IsEnabled="False" Margin="10" SelectedIndex="0">
                <ComboBoxItem Content="McClellan"/>
                <ComboBoxItem Content="Hooker"/>
                <ComboBoxItem Content="Meade"/>
            </ComboBox>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="IsEnabled=true" IsEnabled="True" Margin="10"/>
            <Label Content="IsEnabled=false" IsEnabled="False" Margin="10"/>
        </StackPanel>
    </StackPanel>

#639 – Default Tab Order Is Sensible

In WPF, you can use the Tab key to cycle through all of the focusable controls in a window, changing which control currently has focus.

You normally don’t need to worry about the tab order for controls in a window or page because WPF sets the tab order to match the logical tree.  If you start an application and press the Tab key, the first control in the logical tree will receive focus.

If you then continue to press Tab, each control in the logical tree that has its IsTabStop property set will receive focus.  The order will match the logical tree, starting at the top-level parent and working in a depth-first fashion through all child controls.

In the example below, we have several nested StackPanelin a window.  The numbers indicate the effective tab order.

#623 – Focusable Property Indicates Whether a Control Can Receive Focus

All controls that derive from UIElement have a Focusable property that indicate whether or not they are allowed to have focus.  This property defaults to a value that makes sense for each type of control, given whether a control is meant to allow a user to interact with it by pressing keys.

Here’s a summary of some common user interface elements, with their default values for Focusable.

Elements that have Focusabletrue by default:

  • Button
  • Calendar
  • ComboBox
  • DataGrid
  • DatePicker
  • ListBox
  • RichTextBox
  • Slider
  • TabControl
  • TextBox
  • TreeView
  • Window

Elements that have Focusablefalse by default:

  • Canvas
  • DockPanel
  • Grid
  • Image
  • Label
  • ProgressBar
  • ScrollBar
  • Separator
  • Subclasses of Shape (Ellipse, Line, Path, Polygon, Polyline and Rectangle)
  • StackPanel
  • TextBlock
  • UniformGrid
  • Viewport3D
  • WrapPanel

#311 – Giving Focus to a Control, Part II

You can give focus to a specific control at run-time using the Keyboard.Focus static method.  You can also give focus to any control that inherits from UIElement using the control’s Focus method.

		public MainWindow()
		{
			this.InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);

		}

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // On startup, set focus to first TextBox in window
            txtFirst.Focus();
        }

The difference between these two methods is:

  • Keyboard.Focus just sets keyboard focus
  • UIElement.Focus tries to set keyboard focus.  If the control fails to get keyboard focus, the method sets logical focus to the control

#310 – Give a Control Logical Focus

You can give a control the keyboard focus using the static Keyboard.Focus method.  If you want to instead give a control the logical focus, you can use the FocusManager.SetFocusedElement static method.  (In the System.Windows.Input namespace).

                // Give logical focus to txtFirst TextBox
                DependencyObject focusScope = FocusManager.GetFocusScope(txtFirst);
                FocusManager.SetFocusedElement(focusScope, txtFirst);

If you do this in an application with multiple windows and you set logical focus for a control in the inactive window, you’ll see that it does not get keyboard focus.  You can continue entering text in a control in the active window.  But when you switch back to the inactive window, you’ll see that the control does get keyboard focus.

#309 – Keyboard Focus vs. Logical Focus

In WPF, there are two types of focus–keyboard focus and logical focus.

If an element has keyboard focus, it is the element that can currently receive input from the keyboard.  Only a single element in an entire application can have keyboard at any given time.

An element has logical focus if it is the element within a focus scope that has focus.  The idea is that WPF keeps track of one or more groups of controls, each of which makes up a focus scope.  Within each focus scope, a single control can have logical focus.  This allows WPF to remember the control that last had focus in a group of controls and give the keyboard focus back to the proper control when a group of controls becomes active again.

An element that has keyboard focus always has logical focus.  An element that has logical focus may not have keyboard focus.

#308 – Checking to See Which Control Has Keyboard Focus

You can use the Keyboard.FocusedElement static property (in System.Windows.Input namespace) to determine which control currently has focus.

Here’s an example:

        private void DumpFocus()
        {
            IInputElement elem = Keyboard.FocusedElement;

            if (elem == null)
                Debug.WriteLine("Nobody has focus");
            else
            {
                FrameworkElement felem = elem as FrameworkElement;
                if (felem != null)
                {
                    string identifier = ((felem.Name != null) && (felem.Name.Length > 0)) ?
                        felem.Name :
                        felem.GetType().ToString();
                    Debug.WriteLine(string.Format("FrameworkElement - {0}", identifier));
                }
                else
                {
                    // Maybe a FrameworkContentElement has focus
                    FrameworkContentElement fcelem = elem as FrameworkContentElement;
                    if (fcelem != null)
                    {
                        string identifier = ((fcelem.Name != null) && (fcelem.Name.Length > 0)) ?
                            fcelem.Name :
                            fcelem.GetType().ToString();
                        Debug.WriteLine(string.Format("FrameworkContentElement - {0}", identifier));
                    }
                    else
                    {
                        Debug.WriteLine(string.Format("Element of type {0} has focus", elem.GetType().ToString()));
                    }
                }
            }
        }

#307 – Giving Focus to a Control When an Application Starts

A WPF application does not automatically gives keyboard focus to any single control when the application starts.  You can force a control to get focus at application startup by using the Keyboard.Focus static method (in the System.Windows.Input namespace).

Here’s an example that sets focus to one of the TextBox controls in the main window.

        public MainWindow()
        {
   	        this.InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // On startup, set focus to my first TextBox
            Keyboard.Focus(txtFirst);
        }