#647 – You Can Treat Any Key As A Toggle Key

You typically use the IsToggled property in a keypress handler to check the state of a toggle key like Caps Lock.  But WPF actually keeps track of a “toggled” state for every key that you press.

For example, if you press the letter ‘a’ a number of times in a TextBox and look at the value of the IsToggled property, you’ll see that the property switches between true/false values.  WPF is keeping track of the “toggled” state for the ‘a’ key, even though it’s not normally used as a toggle key.

        private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            Trace.WriteLine(string.Format("----- PreviewKeyDown for key {0}, toggled = {1}", e.Key, e.IsToggled));
        }

#646 – Detecting a Key’s Toggle State in a Keypress Handler

There are several keys on the keyboard that typically act as toggles–when you first press the key, it is considered toggled, or on–and when you press it again, it is considered untoggled, or off.

The keys that are typically used as toggle keys are: Caps Lock, Scroll Lock and Num Lock.  (Note–the normal Shift key is not typically used as a toggle key).

When a key is pressed, you can determine whether it is entering the toggled state or the untoggled state by checking the KeyEventArgs.IsToggled property in one of the keypress event handlers.

        private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            Trace.WriteLine(string.Format("----- PreviewKeyDown for key {0}, toggled = {1}", e.Key, e.IsToggled));
        }

For example, if I press the Caps Lock four times, I’ll see the following output:

The Caps Lock key is toggling on and off.

#645 – Checking for the Presence of Modifier Keys

In Windows, a modifier key is a key that you press in combination with another key.  The standard modifier keys in Windows are:

  • Alt key
  • Control (Ctrl) key
  • Shift key
  • Windows key (Windows logo on face of key)

In a WPF keypress handler (PreviewKeyDown, KeyDown, PreviewKeyUp and KeyUp), you can check for the presence of one of the modifier keys using the KeyEventArgs.KeyboardDevice.Modifiers property.  This property is an enumerated type that is a bitwise combination of the possible values.  You can check for the presence of one of the modifiers by doing an AND operation against the modifier.

        private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            Trace.WriteLine(string.Format("----- PreviewKeyDown for key {0}", e.Key));

            // Dumping out all modifiers
            Trace.WriteLine(string.Format("  KeyboardDevice.Modifiers = {0}", e.KeyboardDevice.Modifiers);

            // Checking for specific modifiers
            if ((e.KeyboardDevice.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
                Trace.WriteLine(" Alt key !");

            if ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
                Trace.WriteLine(" Ctrl key !");
        }

Pressing Ctrl+Alt+G yields:

#644 – Disabling and Hiding Controls

You can disable a control by setting its IsEnabled property to false.  Disabled controls cannot receive input, but are still displayed in the user interface, typically greyed out.

Below is an example of some typical controls, showing what they looked like when enabled vs. disabled.

In addition to disabling a control, you can also make the entire control invisible, using the Visibility property.  Controls that are not visible can be one of:

  • Hidden – Control is not visible, but it still takes up space in the user interface.  I.e. There is whitespace where the control would be if it were visible
  • Collapsed – Control is not present at all in the user interface and neighboring controls fill in the space where the control would be if it were visible

 

 

#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>

#642 – Focusable and IsTabStop in Combination

A control can only accept user input via the keyboard if its Focusable property is set to true.  A control can be tabbed to and accept input only if both the Focusable and IsTabStop properties are true.

This means that if Focusable is false, the IsTabStop property is ignored.

#641 – The Difference Between IsTabStop and Focusable

The Focusable property for a control indicates whether the control can receive focus, which means that the control can receive keyboard input after the user clicks on the control.

Focusable is normally set to true for controls that are designed to accept user input.

The IsTabStop property, on the other hand, indicates that a control is part of the set of controls that are visited when the user cycles focus using the Tab key.

By default, controls whose Focusable property is set to true will also have their IsTabStop property set to true.  You can change this however.  If you set IsTabStop to false, but leave Focusable set to true, the user can click on a control to give it focus, but can’t tab to the control.

#640 – Set the TabIndex Property to Change Tab Order

By default, the sequence of controls that get keyboard focus when the user clicks on the Tab key is based on their order in the logical tree.

If you want to change this Tab order, however, you can set the TabIndex property of each control.  The TabIndex value should start a 0 for the first control that should receive focus and then proceed sequentially, i.e. 1, 2, 3, etc.  Controls with a lower TabIndex will therefore get focus before controls with a higher TabIndex.

    <StackPanel Orientation="Vertical">
        <Button Content="Harpo" TabIndex="1" HorizontalAlignment="Center" Margin="5"/>
        <Button Content="Chico" TabIndex="0" HorizontalAlignment="Center" Margin="5"/>
        <Button Content="Groucho" TabIndex="2" HorizontalAlignment="Center" Margin="5"/>
    </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.

#638 – PreviewTextInput Is Not Fired In Many Cases

You’d normally use the PreviewTextInput event to filter data being entered into a text-based control like the TextBox.  But the PreviewTextInput event is fired for text that is being added to the control, but not fired for certain keypresses that could also result in changes to the text.

Key presses that do not result in the PreviewTextInput event being fired include:

  • Spacebar
  • Backspace
  • Home/End/Delete/Insert keys
  • Arrow keys
  • Control key combinations, including Ctrl+V

This means that if you were only validating text input in PreviewTextInput, a user could use Ctrl+V to do a paste operation into a TextBox and you wouldn’t get a chance to validate the text being added.

All of these key press do result in the PreviewKeyDown event being fired.  This means that to do complete validation of all changes to a TextBox, you’ll likely want to do some validation in PreviewTextInput and some additional validation in PreviewKeyDown.