然后再次。使DropDownButton在mouseEnter上打开并在鼠标离开时隐藏

时间:2016-06-27 09:16:39

标签: c# wpf

我正在使用MahApps和MVVM Light。我想在鼠标输入时打开DropDownButton。当鼠标光标离开按钮并打开菜单时隐藏它。为了简化代码,我不用EventToCommand编写代码。我只是写代码

XAML

                <controls:DropDownButton x:Name="ddbVolume" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}"
                                     ItemsSource="{Binding AudioControls}"
                                     Icon="{DynamicResource appbar_settings}" BorderThickness="0"
                                     ArrowVisibility="Collapsed" 
                                     Loaded="OnDropDownButtonLoaded" MouseEnter="OnDropDownButtonMouseEnter">

            </controls:DropDownButton>

和.cs

    private void OnDropDownButtonMouseEnter(object sender, MouseEventArgs e)
    {
        var dropDownButton = sender as DropDownButton;
        if (dropDownButton != null && !dropDownButton.IsExpanded)
        {
            dropDownButton.IsExpanded = true;
        }
    }

    private void OnDropDownButtonLoaded(object sender, RoutedEventArgs e)
    {
        var dropDownButton = sender as DropDownButton;
        if (dropDownButton != null)
        {
            var template = dropDownButton.Template;
            var menu = (ContextMenu)template.FindName("PART_Menu", dropDownButton);
            menu.MouseLeave += (o, args) =>
            {
                if (dropDownButton.IsExpanded && !dropDownButton.IsMouseOver && !menu.IsMouseOver)
                {
                    dropDownButton.IsExpanded = false;
                }
            };
            menu.PreviewMouseMove += (o, args) =>
            {
                if (!dropDownButton.IsExpanded)
                {
                    return;
                }

                var x = args.GetPosition(menu).X;
                var y = args.GetPosition(menu).Y;
                if (x < 0 | y < 0 | x > menu.ActualWidth | y > menu.ActualHeight)
                {
                    menu.ReleaseMouseCapture();
                }
            };
        }
        else
        {
            this._logger.Debug($"Error loading DropDownButton");
        }

但它不起作用。 DropDownButton只在鼠标悬停时闪烁。请给我一个合适的解决方案,或任何有用的建议来解决这个问题。

3 个答案:

答案 0 :(得分:0)

如果菜单完全出现,那么你的开放逻辑是好的,但它会消失,这意味着你自己的代码以某种方式关闭它。

在你设置dropDownButton.IsExpanded = false的行上贴一个断点,你会看到它被调用我确定。然后,您可以使用调试器来查看为什么调用它并修复xaml中导致系统认为您的鼠标已离开菜单的问题。

答案 1 :(得分:0)

也许,你应该订阅MouseLeave事件。你可以修复你的行动。

答案 2 :(得分:0)

我已经找到了解决方案。它像我期望的那样工作。问题的根源是,DropDownButton使用ContextMenu来显示列表项。此控件基于Popup,后者使用自己的窗口。并且当鼠标光标没有超过它时,MouseLeave没有及时触发,但是当它失去焦点时。

XAML

                <controls:DropDownButton x:Name="ddbVolume" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}"
                                     ItemsSource="{Binding AudioControls}"
                                     Icon="{DynamicResource appbar_settings}" BorderThickness="0"
                                     ArrowVisibility="Collapsed">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Loaded">
                        <command:EventToCommand Command="{Binding Source={x:Static commands:CommonCommands.DropDownButtonLoadedCommand}}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseEnter">
                        <command:EventToCommand Command="{Binding Source={x:Static commands:CommonCommands.DropDownButtonMouseEnterCommand}}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>

            </controls:DropDownButton>

ViewModel代码(我知道它不是VM,但它的工作方式相同) 在静态类中,我定义了可以在我的应用程序的任何地方使用的命令。

 public static class CommonCommands
{
    private static ICommand dropDownButtonLoadedCommand;
    private static ICommand dropDownButtonMouseEnterCommand;

    public static ICommand DropDownButtonLoadedCommand => dropDownButtonLoadedCommand;
    public static ICommand DropDownButtonMouseEnterCommand => dropDownButtonMouseEnterCommand;

    static CommonCommands()
    {
        dropDownButtonLoadedCommand = new RelayCommand<RoutedEventArgs>(DropDownButtonLoaded, x => true);
        dropDownButtonMouseEnterCommand = new RelayCommand<MouseEventArgs>(DropDownButtonMouseEnter, x => true);
    }

    private static void DropDownButtonLoaded(RoutedEventArgs args)
    {
        var dropDownButton = args.Source as DropDownButton;
        if (dropDownButton != null)
        {
            var template = dropDownButton.Template;
            var menu = (ContextMenu)template.FindName("PART_Menu", dropDownButton);
            var button = (Button)template.FindName("PART_Button", dropDownButton);
            menu.MouseLeave += (o, e) =>
            {
                if (dropDownButton.IsExpanded && !dropDownButton.IsMouseOver && !menu.IsMouseOver)
                {
                    dropDownButton.IsExpanded = false;
                }
            };
            menu.PreviewMouseMove += (o, e) =>
            {
                if (!dropDownButton.IsExpanded || !menu.IsOpen)
                {
                    return;
                }

                var x = e.GetPosition(menu).X;
                var y = e.GetPosition(menu).Y;
                if (x < 0 | y < -button.ActualHeight | x > menu.ActualWidth | y > menu.ActualHeight)
                {
                    menu.ReleaseMouseCapture();
                }
            };
        }
    }

    private static void DropDownButtonMouseEnter(MouseEventArgs args)
    {
        var dropDownButton = args.Source as DropDownButton;
        if (dropDownButton != null && !dropDownButton.IsExpanded)
        {
            dropDownButton.IsExpanded = true;
        }
    }
}

我知道有一些小缺陷。例如,“表达式y&lt; -button.ActualHeight”并不是很好。正确的方法是在MouseLeave事件中使用button.IsMouseOver。