views:

27

answers:

0

I have a ListBox with a custom data template which contains a CheckBox, a TextBlock and a TextBox. Normally when you select an item in a ListBox, the underlying ListBoxItem is actually what has the focus and as such, it responds to the up and down keys. Additionally, if the CheckBox has focus, since it doesn't do anything with the up and down keys itself, it just happily ignores them and they're handled by the underlying ListBoxItem as well. All's good so far.

However, a TextBox has its own processing rules for the up and down keys, namingly moving the caret up or down a line in text, which doesn't apply here because in this case it's a single line (it's a number actually.) As such, if the TextBox has focus, the up and down keys break the navigation of the ListBox's selection, nor do they really help with editing.

Now while I could handle the PreviewKeyDownEvent (which I do below, but for different reasons) and manually process the behaviors depending on the pressed keys, that's a very specific solution and requires the control to have knowledge of its container's behavior.

In a perfect world (and in pseudocode), I'd like to just say MyTextBox.KeysToIgnore(Up, Down) or something similar and have it do just that... ignore those keys as if it wasn't even there. (Again, not swallow, but ignore so they pass through.)

But until then, here's what I've come up with, which seems to work, but just looks so 'hacky' to me...

private void PreviewKeyDownHandler(object sender, KeyEventArgs e) {

    switch (e.Key){
        case Key.Up:
        case Key.Down:
        case Key.OtherKeyToIgnore
        case Key.AndAnother

            e.Handled = true;

            FrameworkElement target = VisualTreeHelper.GetParent(
                e.Source as DependencyObject) as FrameworkElement;

            target.RaiseEvent(
                new KeyEventArgs(
                    e.KeyboardDevice,
                    PresentationSource.FromVisual(target),
                    0,
                    e.Key
                ){
                    RoutedEvent=Keyboard.KeyDownEvent
                }
            );
            break;

    }

}

This also has the added negative of not sending the PreviewKeyDown event to the target. Now I could work around that and fake it by sending that event first, then looking at the e.Handled before sending the actual KeyDown message, which makes sense, but then I hit another wall with the PreviewKeyUp and KeyUp events since thanks to setting e.Handled above, I never get the real 'key up' events to know when to send the fake ones. Plus I'm pretty sure I'd also be breaking the direction of the PreviewKeyxxx messages since they bubble the opposite direction from the regular non non-preview versions. (Maybe that's handled internally but I don't think so.)

Like I said... hacky, hacky, hacky!

But it does work so there's that. And I can implement this via Attached Behaviors which is why I even went this route. (In the attached behaviors implementation, it's not a case statement but rather a check against a collection of keys that I specify in XAML.) I just don't like the idea of losing all the other behaviors that I want.

Again, I just want to say 'Hey TextBox... when you see the Up or Down keys being pressed, STFU ya b*stard!!' and otherwise make it key-transparent.

Thoughts anyone?