Retain DataGrid IsSelectionActive when a ContextMenu opens in WPF?

c#, contextmenu, css-selectors, wpf, wpfdatagrid

Solution

Here is an entire XAML that I used in test application to get your desired behavior:

<Window x:Class="DataGridSelectionActive.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataGridSelectionActive"
        Title="MainWindow" Height="350" Width="525">

    <!-- People is just an ObservableCollection derived class. -->
    <Window.DataContext>
        <local:People/>
    </Window.DataContext>

    <Window.Resources>

        <ContextMenu x:Key="dataGridContextMenu">
            <MenuItem Header="Some context menu item"/>
        </ContextMenu>

        <Style TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                    <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                </Trigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True"/>
                        <Condition Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="False"/>
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                    <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                </MultiDataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True"/>
                        <Condition Binding="{Binding ContextMenu.IsOpen, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="True"/>
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                    <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>

    </Window.Resources>

    <DockPanel>
        <!-- Added button for testing keyboard focus. -->
        <Button DockPanel.Dock="Top" Content="Click me"/>
        <DataGrid ItemsSource="{Binding}" ContextMenu="{StaticResource dataGridContextMenu}"/>
    </DockPanel>

</Window>

The key thing that enables this behavior is that if multiple triggers that have conflicting `Setters` are active simultaneously, the last one wins.

Problem

I have a `DataGrid` which has a style for `IsSelectionActive`; however, as soon as the `ContextMenu` opens, the grid loses `IsSelectionActive` and it looks like to the user that as if the context menu somehow took the selection and may confuse the user. Is there a way to retain `IsSelectionActive` when a context menu opens? ``` <ControlTemplate.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <!--<Condition Property="Selector.IsFocused" Value="True" />--> <Condition Property="IsSelected" Value="True" /> </MultiTrigger.Conditions> <Setter Property="Background" Value="Red" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Selector.IsFocused" Value="False" /> <Condition Property="IsSelected" Value="False" /> </MultiTrigger.Conditions> <Setter Property="Background" Value="Green" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Selector.IsFocused" Value="False" /> <Condition Property="IsSelected" Value="True" /> </MultiTrigger.Conditions> <Setter Property="Background" Value="Blue" /> </MultiTrigger> ```

Original source