Как разрешить сетке захватывать мышь, но все же разрешать детям обрабатывать события кликов - PullRequest
0 голосов
/ 31 октября 2018

Извините, если заголовок запутанный. Вот ситуация. У меня есть сетка под названием 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>

Единственное, что я оставил, это словари ресурсов и само определение страницы.

1 Ответ

0 голосов
/ 31 октября 2018

Я думаю, Mouse.Capture и PreviewMouseDownOutsideCapturedElementEvent слишком конкретны для того, что вы хотите.

Я бы предпочел использовать 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;
    }

таким образом, вы также можете удалить вызов Mouse.Capture из btnFilters_Click:

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