简体   繁体   中英

WPF prevent TextBox swallow KeyDown events

I have simple UserControl containing a TextBox . The UserControl also defines some key bindings. However, the TextBox seems to swallow all key presses, prevening said keybindings from ever executing. I have tried marking the PreviewKeyDown events Handled and not Handled, but it does not not seem to have any effect.
How can I prvent TextBox handling selected (eg RightArrow) key events allowing them to bubble up to its parent UserControl ?

<UserControl>
    <UserControl.InputBindings>
        <KeyBinding Key="Right" Command="{Binding TestCommand}"/>
    </UserControl.InputBindings>
    <Grid>
        <TextBox Text="Foo" PreviewKeyDown="TextBox_PreviewKeyDown"
                 FocusManager.FocusedElement="{Binding Path=., RelativeSource={RelativeSource Self}}"/>
    </Grid>
</UserControl>

public partial class UserControl1 : UserControl
{
    private ICommand _testCommand;
    public ICommand TestCommand => _testCommand ?? (_testCommand = new RelayCommand(() =>
    {
        MessageBox.Show("Success!");
    }));

    public UserControl1()
    {
        InitializeComponent();
        DataContext = this;
    }

    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Right)
            e.Handled = false;
    }
}

Is this a similar problem? https://www.codeproject.com/Tips/227733/Passing-events-from-child-to-parent-controls-built

In his case it is a textbox embedded in a listview handling MouseDown, but I think the principle is similar.

The main pain seems to be you need to find the parent control and re-raise the event against it yourself.

In response to a - perfectly valid - point about the fact that links can end up broken, here's the important code from the above. Note: this is dealing with MouseButtons and a TextBox inside a ListView, but the basic principle is the same:

  • Cast sender as appropriate visual control ( TextBox in this case)
  • go upwards/backwards through the visual component tree [using VisualTreeHelper.GetParent(control) ] until you find the parent control you are interested in.
  • Construct appropriate EventArgs -derived class to pass information
  • Manually Raise the event on the parent item.

example:

private void TextBox_MouseDown(object sender, MouseButtonEventArgs e)
{
    ListViewItem lvi = null;
    TextBox tb = sender as TextBox;
    // Get a reference to the parent ListViewItem control
    DependencyObject temp = tb;
    int maxlevel = 0;
    while (!(temp is ListViewItem) && maxlevel < 1000)
    {
        temp = VisualTreeHelper.GetParent(temp);
        maxlevel++;
    }
    lvi = temp as ListViewItem;
    if (lvi != null){
    {
        //Copy over event arg members and raise it
        MouseButtonEventArgs newarg = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, 
                                          e.ChangedButton, e.StylusDevice);
        newarg.RoutedEvent = ListViewItem.MouseDownEvent;
        newarg.Source = sender;
        lvi.RaiseEvent(newarg);
    }
}

It would seem that the author of the codeproject article I linked to is also on gamedev.stackexchange, so credit to XiaoChuan Yu .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM