【问题标题】:How To Let A Grid Capture The Mouse, But Still Allow It's Children To Handle Click Events如何让网格捕获鼠标,但仍允许其子级处理点击事件
【发布时间】:2018-10-31 01:26:46
【问题描述】:

如果标题令人困惑,请提前道歉。这是情况。我有一个名为grdFilters 的网格。该网格中有一系列CheckBoxes(每行一个)。通常这个网格是隐藏的。但我希望它在提示时显示(在按钮单击时),并在用户单击网格以外的某个位置时离开。为了处理外部控制鼠标点击,我首先尝试捕获鼠标:

    AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(HandleClickOutsideOfControl));

    private void HandleClickOutsideOfControl(object sender, MouseButtonEventArgs e)
    {
        if (this.filters) //Check if the Filters grid is visible
        {
            ShowHideMenu("sbHideFilters", grdFilters); //Method that hides the grid
            Mouse.Capture(null); //Release the mouse
        }
    }

    private void btnFilters_Click(object sender, RoutedEventArgs e)
    {
        if (!this.filters) //Check if the filters grid is shown
        {
            ShowHideMenu("sbShowFilters", grdFilters); //Method that reveals the grid
            Mouse.Capture(grdFilters); //Capture the mouse
        }
    }

问题是,当过滤器网格捕获了鼠标时,没有一个子网格(复选框)可以被点击。我真的很想找到一种方法来检测何时在网格外单击鼠标,同时仍允许网格的子级接受鼠标按下事件。任何帮助将不胜感激,在此先感谢。

根据要求,这里是我的一些 Xaml:

<Grid>
    <Label x:Name="label" Content="Events" HorizontalAlignment="Center" VerticalAlignment="Top"/>
    <ScrollViewer HorizontalAlignment="Left" Height="619" Margin="0,26,0,0" VerticalAlignment="Top" Width="450" VerticalScrollBarVisibility="Hidden">
        <Grid x:Name="Schedule" HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" Width="450" Margin="10,0,0,0"/>
    </ScrollViewer>
    <Grid x:Name="grdFilters" HorizontalAlignment="Left" Height="619" Margin="490,26,-176,0" VerticalAlignment="Top" Width="135" Background="{StaticResource TransparentBackground}" Panel.ZIndex="95">
        <CheckBox x:Name="chckAll" Content="All" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Checked="chckAll_Checked" Unchecked="chckAll_Unchecked"/>
        <Grid x:Name="grdFilters" HorizontalAlignment="Left" Height="588" Margin="0,31,0,0" VerticalAlignment="Top" Width="136"/>
    </Grid>
    <Button x:Name="btnFilters" Content="" Margin="436,223,-18,0" VerticalAlignment="Top" Background="Cyan" Opacity="0.15" Style="{StaticResource MyTabStyle}" Height="80" Click="btnFilters_Click"/>

</Grid>

我唯一遗漏的是资源字典和页面定义本身。

【问题讨论】:

  • 你也可以提供 XAML 吗?
  • @P.Manthe Can and did,如果你认为还有什么可以帮助的,请告诉我
  • 你说的网格不是很清楚。您希望能够通过在grdFilters 外部单击来隐藏它,但仍然能够与grdFilters 的子级交互而不隐藏它?
  • @P.Man 正确。此外,当我在其边界内选择时,我不希望它隐藏。由网格 x、y、宽度和高度定义的边界。但是为了让它在我选择它之外时隐藏起来,我仍然必须注册点击并捕获鼠标。但是当我捕获鼠标时,我无法与孩子们互动。如果有另一种不捕获鼠标的方法,如果您认为它更好,我愿意尝试
  • @P.Manthe 我动态创建复选框,这就是它们不在 Xaml 中的原因。如果可以让它们更容易,我可以对它们进行硬编码,或者提供我的代码来动态创建它们,但它有点冗长

标签: c# wpf grid children mousecapture


【解决方案1】:

我认为Mouse.CapturePreviewMouseDownOutsideCapturedElementEvent 过于具体,无法满足您的需求。

我宁愿使用hitResultsList,它可以用于很多不同的场景:

我稍微修改了一下诶AddHandler

AddHandler(Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(HandleMouseDown));

我添加了VisualTreeHelper.HitTest 逻辑

    //List to store all the elements under the cursor
    private List<DependencyObject> hitResultsList = new List<DependencyObject>();

    private void HandleMouseDown(object sender, MouseButtonEventArgs e)
    {

        Point pt = e.GetPosition((UIElement)sender);
        hitResultsList.Clear();

        //Retrieving all the elements under the cursor
        VisualTreeHelper.HitTest(this, null,
            new HitTestResultCallback(MyHitTestResult),
            new PointHitTestParameters(pt));

        //Testing if the grdFilters is under the cursor
        if (!hitResultsList.Contains(this.grdFilters) && grdFilters.Visibility == System.Windows.Visibility.Visible)
        {
            grdFilters.Visibility = System.Windows.Visibility.Hidden;
        }
    }

    //Necessary callback function
    private HitTestResultBehavior MyHitTestResult(HitTestResult result)
    {
        hitResultsList.Add(result.VisualHit);
        return HitTestResultBehavior.Continue;
    }

这样您还可以从 btnFilters_Click 中删除 Mouse.Capture 调用:

    private void btnFilters_Click(object sender, RoutedEventArgs e)
    {
        if (grdFilters.Visibility != System.Windows.Visibility.Visible)
            grdFilters.Visibility = System.Windows.Visibility.Visible; }
    }

【讨论】:

  • 这绝对看起来对我有用。但是,在这种情况下,是什么处理事件HandleMouseDown?哦没关系我看到了,一开始是通过AddHandler添加的,我马上试试。
  • 哇,效果非常好,谢谢。我以前从未使用过 VisualTreeHelper,它看起来非常强大。我将不得不做更多的阅读,以确保我理解必要的回调函数MyHitTestResult,但这已经完美地工作并且给了我一些东西来研究。非常感谢!
猜你喜欢
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多