【问题标题】:Detect global click UWP检测全局点击 UWP
【发布时间】:2017-10-31 15:49:17
【问题描述】:

我有一个可见的网格,当我点击它的外部时它必须折叠。我解决了一半。

MainPage.xaml 代码:

<StackPanel Width="400" VerticalAlignment="Center">
        <Button x:Name="btnOne" Content="Button One" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="30"/>
        <Button x:Name="btnShowGrid" Content="Show Grid" Click="btnShowGrid_Click" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="30"/>
        <Grid x:Name="ControlGrid" PointerEntered="ControlGrid_PointerEntered" PointerExited="ControlGrid_PointerExited" HorizontalAlignment="Center" Visibility="Visible" Background="LightGreen" Height="300" VerticalAlignment="Top" Width="300" Margin="30"/>
</StackPanel>

MainPage.xaml.cs 代码:

    bool PointerInGrid = false;
    public MainPage()
    {
        this.InitializeComponent();
    }
    protected override void OnPointerPressed(PointerRoutedEventArgs e)
    {
        base.OnPointerPressed(e);
        if (!PointerInGrid)
        {
            ControlGrid.Visibility = Visibility.Collapsed;
        }
    }
    private void btnShowGrid_Click(object sender, RoutedEventArgs e)
    {
        ControlGrid.Visibility = Visibility.Visible;
    }
    private void ControlGrid_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        PointerInGrid = true;
    }
    private void ControlGrid_PointerExited(object sender, PointerRoutedEventArgs e)
    {
        PointerInGrid = false;
    }

如果我点击进入网格,它仍然可见,如果我点击出去,网格就会折叠,到目前为止一切都很好,但是,如果我点击 btnOne,网格仍然可见。

那么是否有可能检测到全局单击以折叠网格?

一如既往地提前感谢。

在 windows 窗体中工作的代码:

    const int WM_PARENTNOTIFY = 0x0210;
    const int WM_LBUTTONDOWN = 0x0201;

    public Form1()
    {
        InitializeComponent();
    }

    protected override void WndProc(ref Message m)
    {
        if (!DesignMode)
        {
            if (m.Msg == WM_PARENTNOTIFY)
            {
                if (m.WParam.ToInt32() == WM_LBUTTONDOWN)
                {
                    MessageBox.Show("Clicked!");
                }
            }
        }
        base.WndProc(ref m);
    }

【问题讨论】:

    标签: c# uwp


    【解决方案1】:

    PointerPressed 事件被按钮吞没,因此它无法到达底层父级,事件处理程序 OnPointerPressed 在那里执行。

    有一种技术可以将事件传递给父级,请参考this answer

    你可以这样做,在页面的构造函数中

    public MainPage()
    {
        this.InitializeComponent();
        //...other code
    
        //then add this line
        this.btnOne.AddHandler(UIElement.PointerPressedEvent,
          new PointerEventHandler((s, e) => { e.Handled = false; }), true);
    }
    

    再想一想:也许你可以只处理 btnOne 的 PointerPressed 事件,并在处理程序中将其事件参数的 Handled 属性设置为 false。我的意思是,不需要使用 AddHandler。试试看吧。

    【讨论】:

    • 对于 btnOne 来说是对的。但我想拦截任何点击。我用一个在 Windows 窗体中工作的代码堆栈更新了这个问题,以更好地理解我想要实现的目标。
    • 这种机制,即事件在父级中触发,然后如果父级未处理则传递给子级,称为 事件隧道,就像 WPF 中的 PreviewMouseDown 事件一样,是总是先在父母身上解雇。但是在 UWP 中,似乎不支持隧道,只支持冒泡事件,即事件首先由子进程处理。我认为您提供的 WinForm 示例代码是 Win32 等效的隧道。
    • 那么,对于 UWP 来说,如果您在 UserControl 外部单击,是否有办法关闭它?
    • @LightGreen 考虑使用flyout,它的行为完全符合您的要求。阅读其使用场景的备注。
    • 最后一件事,但是,使用弹出按钮我可以更改关闭动画,然后当我点击它之外?
    【解决方案2】:

    据我所知,UWP 是沙盒的,我们不能使用WndProc 方法来接收窗口事件消息。

    特定的 Windows 运行时控件可能对 PointerPressed 输入事件进行基于类的处理。如果是这样,则该控件可能具有 OnPointerPressed 方法的覆盖。通常,事件由类处理程序标记为已处理,并且不会引发 PointerPressed 事件以供该控件上的任何用户代码处理程序处理。例如,ButtonBase 具有处理 PointerPressed 并触发 Click 的类处理。

    更多信息,请参考PointerPressed

    当我们点击Button时,OnPointerPressed事件不会被触发。

    如果你想让你的Button 可以触发OnPointerPressed 事件,你可以创建一个继承Button 类的类。在类中,您可以覆盖OnPointerPresse 事件。

    例如:

    class MyButton: Button
    {
        protected override void OnPointerPressed(PointerRoutedEventArgs e)
        {
    
        }
    }
    

    顺便说一句,如果我们在继承 Button 类的类中重写 OnPointerPressed 事件,则不会触发 Click 事件。

    【讨论】:

      猜你喜欢
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 2012-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-09
      • 1970-01-01
      相关资源
      最近更新 更多