Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF防止控件外的事件冒泡_Wpf_Events_Routed Commands - Fatal编程技术网

WPF防止控件外的事件冒泡

WPF防止控件外的事件冒泡,wpf,events,routed-commands,Wpf,Events,Routed Commands,让我们从元素树开始。最上面的元素是一个WPF窗口,它已注册ApplicationCommands.Find命令。 某些子元素具有键绑定,且手势键ENTER指向此命令。这是确定的,如果有人按下回车键,命令将被执行。 其中我有一个自定义控件,带有用于搜索和选择某些元素的弹出窗口。但是在这个地方, 我不希望在自定义控件之外允许密钥事件冒泡。但是我为设置了e.handled=true KeyDown+=newkeyeventHandler(..),它应该是一个冒泡路由事件,该自定义控件内的所有控件(文本

让我们从元素树开始。最上面的元素是一个WPF窗口,它已注册
ApplicationCommands.Find
命令。 某些子元素具有键绑定,且手势键ENTER指向此命令。这是确定的,如果有人按下回车键,命令将被执行。 其中我有一个自定义控件,带有用于搜索和选择某些元素的弹出窗口。但是在这个地方, 我不希望在自定义控件之外允许密钥事件冒泡。但是我为设置了
e.handled=true
KeyDown+=newkeyeventHandler(..)
,它应该是一个冒泡路由事件,该自定义控件内的所有控件(文本框等)将忽略任何类型的输入。 但我只想在CustomControl级别停止冒泡,换句话说:从叶子到最顶端的控件父级,而不是更远! 为什么呢?我没有筛选
PreviewKeyDown
,因此事件必须一直传播到叶,然后它应该返回到父级,但它不会

多谢各位

编辑:示例代码:

<UserControl x:Class="WpfApplication5.TestUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    <StackPanel Orientation="Vertical">        
        <TextBox />
        <TextBox />
        <TextBox />
    </StackPanel>
</UserControl>


/* 
 * I want to stop bubbling at this level. Let us say if we click 'enter' on the level of the TextBox leaf, 
 * it should propagate until the TestUserControl is reached and then stop.
 */
public partial class TestUserControl : UserControl
{
    public TestUserControl()
    {
        InitializeComponent();
    }
}


<Window x:Class="WpfApplication5.Window6"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication5"
    Title="Window6" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Find" Executed="CommandBinding_Executed" />
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Gesture="Enter" Command="ApplicationCommands.Find" />
    </Window.InputBindings>
    <Grid>
        <local:TestUserControl />
    </Grid>
</Window>

public partial class Window6 : Window
{
    public Window6()
    {
        InitializeComponent();
    }

    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        MessageBox.Show("Executed");
    }
}

/* 
*我想在这个水平上停止冒泡。比如说,如果我们在文本框叶的级别上单击“回车”按钮,
*它应该传播到TestUserControl,然后停止。
*/
公共部分类TestUserControl:UserControl
{
公共TestUserControl()
{
初始化组件();
}
}
公共部分类Window6:Window
{
公共窗口6()
{
初始化组件();
}
已执行私有无效命令绑定(对象发送方,已执行路由目标)
{
MessageBox.Show(“已执行”);
}
}

您希望将事件从自定义控件桥接到窗口,对吗? 然后必须从窗口重新启动事件,系统才能处理它。如果只将其标记为已处理,则表示不会采取进一步的操作

代码应该是这样的:

private void CustomControl_KeyDown(object sender, KeyEventArgs e)
{
    e.Handled = true;
    var relaunchedEvent = new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key);
    relaunchedEvent.RoutedEvent = Keyboard.KeyDownEvent;
    relaunchedEvent.Source = e.OriginalSource;
    TopMostWindow.RaiseEvent(relaunchedEvent);
} 
--编辑--

使用下面的xaml测试上面的代码,以查看在不执行命令的情况下如何在窗口中触发keydown事件

<Window x:Class="WpfApplication5.Window6"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication5"
    Title="Window6" Height="300" Width="300"
    x:Name="TopMostWindow">
    <Grid>
        <Grid KeyDown="CustomControl_KeyDown">
            <local:UserControl1/>
        </Grid>
        <Grid.CommandBindings>
            <CommandBinding Command="ApplicationCommands.Find" Executed="CommandBinding_Executed" />
        </Grid.CommandBindings>
        <Grid.InputBindings>
            <KeyBinding Key="Enter" Command="ApplicationCommands.Find" />
        </Grid.InputBindings>
    </Grid>
</Window>

重要注意事项:

  • 命令处于更高的级别,因此无论是使用冒泡事件还是隧道事件,最终都会执行命令,除非事件标记为已处理
  • 引发Keydown事件实际上并不意味着按下该键,因为不会进行文本合成

对于您的情况,我的建议是过滤用户控件中的keydown事件,如果
e.Key=Key.Enter,则将其标记为已处理,因为Enter对文本框没有太大作用。否则,您必须模拟按键。

不完全如此。我想停止将事件从自定义控件传播到主窗口。。但是谢谢你谢谢你的编辑,但是如果密钥是Key=“f”呢?我无法筛选此键,因为“f”是文本框的有效输入。问题是,我无法强制此控件的用户手动处理KeyDown事件,因为我的控件会出现一些未处理的事件。抓住它,在正确的地方重新起跳。。这不好。你不这么认为吗?用户应该明白,如果他在窗口上放置了一个按键事件的命令,并且需要对其中的任何控件执行不同的行为,那么问题就出在他身上。如果该键是文本框的有效输入,你就必须模拟控件上的按键,你可能会发现如何输入,但我相信这并不简单。