Question

I have a program that contains a textbox control. A user is able to enter text into this control. The user can also press certain keys to trigger other actions (this is handled on the MainWindow). I have sample XAML and C# code to demonstrate my setup.

XAML

<Window x:Class="RoutedEventBubbling.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>

        <TextBox Grid.Row="0" />
        <TextBox x:Name="Output" Grid.Row="1" IsReadOnly="True" />
    </Grid>
</Window>

C#

using System.Windows;
using System.Windows.Input;

namespace RoutedEventBubbling
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int mHitCount = 0;

        public MainWindow()
        {
            InitializeComponent();
        }

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

            this.Output.Text = string.Format("Hit Count: {0}", ++mHitCount);
        }
    }
}

As you may have realised, in the case of this program, if I start typing into the first TextBox the second will be updated with the hit count. This is an undesirable result as I might have certain actions that I wish to trigger when handling the MainWindow's OnKeyDown method.

As such, my question is this: is it possible to prevent the OnKeyDown method being called on the MainWindow, while still allowing text to be entered into the text box? I know of the e.Handled = true approach, but in this case doing that on the KeyDown event of the TextBox will prevent the text from being entered. If this is not possible, I will have to find some other way of handling it all.

Thanks in advance.

EDIT

I have just found a moderately hacky way around this issue. If I handle the MainWindow's OnTextInput method instead, then the result I desired will be achieved as the TextInput event of the TextBox will have been handled. Below is a sample of the code I used:

private Key mPressedKey;

protected override void OnKeyDown(KeyEventArgs e)
{
    // Note: This method will be called first.

    base.OnKeyDown(e);

    // Store the pressed key
    mPressedKey = e.Key;
}

protected override void OnTextInput(TextCompositionEventArgs e)
{
    // Note: This method will be called second, and only if the textbox hasn't handled it.

    base.OnTextInput(e);

    this.Output.Text = string.Format("Hit Count: {0}", ++mHitCount);

   // ... Handle pressed key ...
}
Was it helpful?

Solution 2

I ended up working around this issue using the following setup:

private Key mPressedKey;

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

    mPressedKey = e.Key;
}

protected override void OnTextInput(TextCompositionEventArgs e)
{
    base.OnTextInput(e);

    // ... Handle mPressedKey here ...
}

protected override void OnMouseDown(MouseButtonEventArgs e)
{
    base.OnMouseDown(e);

    // Force focus back to main window
    FocusManager.SetFocusedElement(this, this);
}

This was done in the MainWindow.xaml.cs. It's a bit of a hack, but it achieved the result I wanted.

OTHER TIPS

You could put a type-based guard on that statement:

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

    if (e.OriginalSource is TextBoxBase == false)
    {
        mPressedKey = e.Key;
    }
}

Quite possibly not the best solution either though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top