#631 – Event Sequence for KeyPressUp, KeyPressDown and TextInput

The full event sequence for keyboard related events is shown below, as they propagate down (tunneling) or up (bubbling) the logical tree.

If we have a Window that contains a StackPanel, which in turn contains a TextBox, the sequence of events would be:

  • Window_PreviewKeyDown
  • StackPanel_PreviewKeyDown
  • TextBox_PreviewKeyDown
  • TextBox_KeyDown
  • StackPanel_KeyDown
  • Window_KeyDown
  • Window_PreviewTextInput
  • StackPanel_PreviewTextInput
  • TextBox_PreviewTextInput
  • TextBox_TextInput – suppressed/handled
  • StackPanel_TextInput – suppressed/handled
  • Window_TextInput – suppressed/handled
  • Window_PreviewKeyUp
  • StackPanel_PreviewKeyUp
  • TextBox_PreviewKeyUp
  • TextBox_KeyUp
  • StackPanel_KeyUp
  • Window_KeyUp

Note that the TextInput event is listed, since TextInput events would normally fire for the originating control and then propagate up the logical tree.  But in the case of TextBox, the TextInput event is marked as handled and therefore does not fire.

Advertisement

#628 – Key Up/Down Sequence When Using ALT Key

When you use the Alt-key in combination with another key, the control that has focus will receive KeyUp and KeyDown events for both the Alt key and the combination key.

When using the Alt key, the Key property of the KeyEventArgs object will be Key.System and the actual key being pressed will be available in the SystemKey property.  This is true for both the Alt key and the combination key.

For example, pressing Alt-Q while a TextBox control has focus will result in the following events for the TextBox, in the sequence listed.

  • PreviewKeyDown, Key = System, SystemKey = LeftAlt
  • KeyDown, Key = System, SystemKey = LeftAlt
  • PreviewKeyDown, Key = System, SystemKey = Q
  • KeyDown, Key = System, SystemKey = Q
  • PreviewKeyUp, Key = System, SystemKey = Q
  • KeyUp, Key = System, SystemKey = Q
  • PreviewKeyUp, Key = System, SystemKey = LeftAlt
  • KeyUp, Key = System, SystemKey = LeftAlt

#626 – Key Up/Down Sequence When Using CTRL Key

When you use the Ctrl-key in combination with another key, e.g. pressing Ctrl-G, the control that has focus will receive KeyUp and KeyDown events for both the Ctrl key and the main key that you are pressing.

For example, if a TextBox control has focus and I press Ctrl-G (which doesn’t normally do anything in a TextBox) and I use the Ctrl key on the left side of the keyboard, I’ll see the following events for the TextBox, in the sequence listed.

  • PreviewKeyDown, key = LeftCtrl
  • KeyDown, key = LeftCtrl
  • PreviewKeyDown, key = G
  • KeyDown, key = G
  • PreviewKeyUp, key = G
  • KeyUp, key = G
  • PreviewKeyUp, key = LeftCtrl
  • KeyUp, key = LeftCtrl

In this case, you can see that my sequence in pressing/releasing the keys was:

  • Press and hold left Ctrl key
  • Press G key
  • Release G key
  • Release Ctrl key

#624 – Information Available to Key Up/Down Events

All four of the keypress-related events (PreviewKeyDown, KeyDown, PreviewKeyUp, and KeyUp) send an instance of the KeyEventArgs object to the associated event handler.

private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
}

Here are some of the more important properties available in the KeyEventArgs object:

  • Key property – The System.Windows.Input.Key being pressed.  E.g. Key.Q
  • Timestamp – Time of key press, in # ticks (milliseconds) since last reboot
  • IsDown / IsUp – Is the key currently down or up?
  • IsRepeat – Is this keystroke a repeat due to holding a key down?
  • IsToggled – For keys that toggle, like Caps Lock, indicates current toggled state
  • Source – The control that had focus when the key was pressed
  • OriginalSource – Either the control where the key was pressed, or a lower-level child element
  • Handled – Can set to true to indicate that you’ve handled the event, short-circuiting the event routing (generally)

#621 – An Example of Handling Preview Keypress Events

Below is an example of handling both PreviewKeyUp and KeyUp events.  The PreviewKeyUp is used to completely block a particular key (the letter ‘E’).  The KeyUp event is used to trigger an update to a calculated property.

    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal"
                    PreviewKeyDown="StackPanel_PreviewKeyUp">
            <Label Content="First Name:" VerticalAlignment="Center"/>
            <TextBox Margin="5" Width="100" Height="25"
                     Text="{Binding Path=FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                     KeyUp="txtFirst_KeyUp"/>
            <Label Content="Last Name:" VerticalAlignment="Center"/>
            <TextBox Margin="5" Width="100" Height="25"
                     Text="{Binding Path=LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                     KeyUp="txtLast_KeyUp"/>
        </StackPanel>
        <Label Content="{Binding FullName}"/>
        <Label Content="{Binding LastChanged}"/>
    </StackPanel>

 

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string FullName { get; set; }
        public string LastChanged { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            CalcFullName();
        }

        private void StackPanel_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            // E's are not allowed !
            if (e.Key == Key.E)
                e.Handled = true;
        }

        private void txtFirst_KeyUp(object sender, KeyEventArgs e)
        {
            CalcFullName();
            LastChanged = "Changing FIRST Name";
            RaisePropertyChanged("LastChanged");
        }

        private void txtLast_KeyUp(object sender, KeyEventArgs e)
        {
            CalcFullName();
            LastChanged = "Changing LAST Name";
            RaisePropertyChanged("LastChanged");
        }

        private void CalcFullName()
        {
            FullName = string.Format("Full Name: [{0} {1}]", FirstName, LastName);
            RaisePropertyChanged("FullName");
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }

    }

#620 – Why Are There So Many KeyPress Events?

When you press a single key within a WPF application, there are potentially a number of different keypress events that can fire.  But why are there so many different events that can possibly fire?

There are several reasons why there isn’t just a single keypress event.

  • Your application will only see the events for which you define a handler.  There is a large set of possible events so that you can choose which ones make sense for your application to handle.
  • Preview events exist so that a parent control can intercept keypress events for its children or descendants.  The tunneling allows you to decide at what level you want to preview the event.
  • The actual keypress event bubbles up the logical tree so that you can decide at what level to actually respond to the event.  In this way, you can handle multiple events in a single place.

#619 – Event Sequence for the Key Up/Down Events

There are four basic events related to a key being pressed or released that a GUI element can fire in WPF.  An event fires when you press a key down (KeyDown) and a different event fires when you release the key (KeyUp).  When these events fire for an element, they fire first for the element and then work back up the logical tree, firing for each ancestor element.  These are bubbling events.

There are also the PreviewKeyDown and PreviewKeyUp events, which fire before the KeyDown and KeyUp events, but fire from the top of the logical tree down to the control where the event originated.  (Tunneling events).

For a Window containing a StackPanel that contains a TextBox, the event sequence when a user presses a key while the TextBox has focus is:

  • Window_PreviewKeyDown
  • StackPanel_PreviewKeyDown
  • TextBox_PreviewKeyDown
  • TextBox_KeyDown
  • StackPanel_KeyDown
  • Window_KeyDown
  • Window_PreviewKeyUp
  • StackPanel_PreviewKeyUp
  • TextBox_PreviewKeyUp
  • TextBox_KeyUp
  • StackPanel_KeyUp
  • Window_KeyUp

 

#204 – Detecting Key Presses in a WPF Window

You can detect key presses in a class that derives from Window by overriding the OnKeyDown and OnKeyUp methods (which in turn fire the KeyDown and KeyUp events).  

These key down/up methods are invoked in addition to any control that has focus and might also provide key down/up methods.

For example, a TextBox also has KeyDown and KeyUp events that are fired.  If a user presses a key while a TextBox has focus, the sequence of events is:

  • KeyDown in TextBox
  • KeyDown in Window
  • KeyUp in TextBox
  • KeyUp in Window

Here’s an example:

    public partial class MainWindow : Window
    {
        private static Key[] vowels = { Key.A, Key.E, Key.I, Key.O, Key.U };

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            if ((vowels.Contains(e.Key)) && (!e.IsRepeat))
                lblVowels.Content = lblVowels.Content + e.Key.ToString();
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);

            if (vowels.Contains(e.Key))
                lblVowels.Content = lblVowels.Content + ",";
        }