Search code examples
wpfxamlmenumouseover

WPF MouseOver MenuItem prevents focus from returning to window


I have a Window with a custom menu and a few buttons. I have made the menu expand automatically when the user places the mouse over a menu item. Each of the buttons has a "mouse hover" state. My problem is that after I open the menu by hovering over it, the buttons no longer show the "mouse hover" state.

Here's a simplified version of my window:

<Window>
    <Button Cursor="Hand" Width="20" Height="20">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="White" />
                <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="Border" Background="{TemplateBinding Background}" CornerRadius="30">
                            <Image Source="../Icons/close.png" Width="9" Height="9" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
                </Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="Gray" />
                </Trigger>
            </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

    <ScrollViewer>
        <Menu ItemsSource="{Binding Path=CommandMenuItems}">
            <Menu.ItemContainerStyle>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="Focusable" Value="False"/>
                    <Setter Property="Template">
                        <Setter.Value>
                        <ControlTemplate TargetType="{x:Type MenuItem}">
                                             <Border>
                                                 <Grid>
                                                     <ContentPresenter />
                                                     <TextBlock />
                                                     <Grid />
                                                     <Popup IsOpen={Binding IsSubmenuOpen}"/>
                                                 </Grid>
                                             </Border>
                                <ControlTemplate.Triggers>
                                    <MultiTrigger>
                                        <MultiTrigger.Conditions>
                                            <Condition Property="IsMouseOver" Value="True" />
                                            <Condition Property="Role" Value="SubmenuHeader" />
                                        </MultiTrigger.Conditions>
                                        <Setter Property="IsSubmenuOpen" Value="True" />
                                    </MultiTrigger>
                                    <MultiTrigger>
                                        <MultiTrigger.Conditions>
                                            <Condition Property="IsMouseOver" Value="True" />
                                            <Condition Property="Role" Value="TopLevelHeader" />
                                        </MultiTrigger.Conditions>
                                        <Setter Property="IsSubmenuOpen" Value="True" />
                                    </MultiTrigger>
                                        
                                </ControlTemplate.Triggers>

                            </ControlTemplate>
                            </Setter.Value>
                    </Setter>
            </Menu.ItemContainerStyle>
    </ScrollViewer>
</Window>

I have tried to manually set focus back to the window when the popup closes but that has not worked.


Solution

  • I finally found an answer! It turns out that the menu does not release the mouse when the cursor leaves the popup.

    Add a handler to the popup:

    <Popup Closed="PART_Popup_Closed">
        <!-- Popup contents here -->
    </Popup>
    

    And to the handler add:

    private void PART_Popup_Closed(object sender, EventArgs e)
    {
        if(CommandMenu.IsMouseCaptured)
            CommandMenu.ReleaseMouseCapture();
    }
    

    Everything works great now.