1

Sorry in advance if the title is confusing. Here's the situation. I have a grid called grdFilters. This grid has a series of CheckBoxes within it (one per row). Normally this grid is hidden. But I wanted it to show up when prompted (on button click) and leave when the user clicks somewhere other than the grid. To handle outside control mouse clicks I tried first capturing the mouse as such:

    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
        }
    }

The problem is that while the Filters grid has captured the mouse, none of the grids children (the Check Boxes) can be clicked on. I would really like to find a way to detect when the mouse is clicked outside of the grid while still allowing the children of the grid to accept mouse down events. Any help would be greatly appreciated, thanks in advance.

As per request here is some of my 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>

The only thing I left out were the Resource Dictionaries and the page definition itself.

Ryoku
  • 397
  • 2
  • 16
  • Can you provide the XAML also? – P.Manthe Oct 31 '18 at 02:06
  • @P.Manthe Can and did, if there's anything else you think might help please let me know – Ryoku Oct 31 '18 at 02:10
  • It is not really clear of what grid you are talking. You want to be able to hide `grdFilters` by clicking outside of it, but still be able to interact with the children of `grdFilters` without hiding it? – P.Manthe Oct 31 '18 at 02:43
  • @P.Manthe correct. More over I don't want it to hide when I select within its border. The border defined by the grids x, y, width, and height. But in order to make it hide when I select outside of it I still have to register the click and thus capture the mouse. But when I capture the mouse I cannot interact with the children. If there is another way of doing it without capturing the mouse I'm willing to try it if you think its better – Ryoku Oct 31 '18 at 02:48
  • @P.Manthe I dynamically create the check boxes which is why they aren't in the Xaml. I can hard code them if it would make it easier, or provide my code for dynamically creating them but its a bit lengthy – Ryoku Oct 31 '18 at 02:57

1 Answers1

2

I think the Mouse.Capture and PreviewMouseDownOutsideCapturedElementEvent and are too specific for what you want.

I would rather use a hitResultsList, which can be used in a lot of different scenarios:

I slightly modified eh AddHandler

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

And I added the VisualTreeHelper.HitTest logic

    //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;
    }

that way you can also remove the Mouse.Capture call from the btnFilters_Click:

    private void btnFilters_Click(object sender, RoutedEventArgs e)
    {
        if (grdFilters.Visibility != System.Windows.Visibility.Visible)
            grdFilters.Visibility = System.Windows.Visibility.Visible; }
    }
P.Manthe
  • 960
  • 1
  • 5
  • 12
  • This definitely looks like it could work for me. In this case though, what handles the event `HandleMouseDown`? Oh never mind I see it, it's added through AddHandler at the very beginning, I'll try it out right away. – Ryoku Oct 31 '18 at 05:52
  • Wow that works spectacularly thank you. I have never used VisualTreeHelper before, it seems incredibly powerful. I'm gonna have to do a bit more reading to make sure that I understand the necessary callback function `MyHitTestResult` but this has worked perfectly and given me something to look into. Thank you so much! – Ryoku Oct 31 '18 at 06:01