【问题标题】:WPF prevent event bubbling outside of a controlWPF 防止事件在控件外冒泡
【发布时间】:2012-04-25 16:44:43
【问题描述】:

让我们从元素树开始。最上面的元素是一个注册了ApplicationCommands.Find 命令的WPF 窗口。 一些子元素具有 KeyBinding,手势键 ENTER 指向此命令。没关系,如果有人按 ENTER,则将执行该命令。 其中我有一个自定义控件,带有一个用于搜索和选择某些元素的弹出窗口。不过在这个地方, 我不想让自定义控件之外的键事件冒泡。但我将e.handled = true 设置为 KeyDown += new KeyEventHandler (..) 应该是一个冒泡路由事件,该自定义控件内的所有控件(文本框等)将忽略任何类型的输入。 但我只想停止在 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");
    }
}

【问题讨论】:

    标签: wpf events routed-commands


    【解决方案1】:

    您想将事件从您的自定义控件连接到您的窗口,对吗? 然后,您必须从 Window 重新启动该事件,以便系统处理它。如果您仅将其标记为已处理,则意味着不会再进行任何操作。

    代码应该是这样的:

    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 是 Key="f" 怎么办?我无法过滤此键,因为“f”是文本框的有效输入。
    • 重点是,我不能强迫这个控件的用户手动处理 KeyDown 事件,因为我的控件出现了一些未处理的事件。并抓住它并在正确的地方重新投掷......这并不好。你不觉得吗?
    • 用户应该明白,如果他在 Window 上放置 KeyDown 事件的命令并且需要对其中的任何控件进行不同的行为,那么问题就是他的。
    • 如果键是文本框的有效输入,您必须在控件上模拟按键,您可能会在 SO 中找到如何操作,但我相信这不是微不足道的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多