2

我有一个ContextMenuButton想在一个MouseEnter事件上打开的,而不是在默认的右键单击事件上。这是我的 XAML:

<Button Content="Button" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave">
    <Button.ContextMenu>
        <ContextMenu>
            .... context menu items ....
        </ContextMenu>
    </Button.ContextMenu>
</Button>

以及相关的事件处理程序:

private void Button_MouseEnter(object sender, MouseEventArgs e)
{  
    backButtonContextMenu.Placement = PlacementMode.Bottom;
    backButtonContextMenu.IsOpen = true;
    Console.WriteLine("MouseEnter called");
}

private void Button_MouseLeave(object sender, MouseEventArgs e)
{  
    backButtonContextMenu.IsOpen = false;
    Console.WriteLine("MouseLeave called");
}

很直接。不幸的是,当鼠标悬停在按钮上时,这两种方法被无限调用,来回交替。这是我的控制台中的输出示例:

MouseEnter called
MouseLeave called
MouseEnter called
MouseLeave called
MouseEnter called
MouseLeave called
MouseEnter called
MouseLeave called
  ... etc. ...

我假设这与 ContextMenu 在打开时窃取焦点有关,或者可能放置某种不可见的“帮助”背景以检测何时需要关闭。有没有人对这种行为有解释,有没有办法避免它?从 UI 的角度来看,这是一个非常简单的效果。

4

2 回答 2

3

ContextMenu当调用 the时,它​​会进入一个循环 cosButton松开鼠标然后关闭它ContextMenu,现在鼠标再次返回到Button你的循环。

你可以去:

private void Button_MouseLeave(object sender, MouseEventArgs e) {
  if (backButtonContextMenu.IsMouseOver)
    return;
  backButtonContextMenu.IsOpen = false;
  Debug.WriteLine("MouseLeave called");
}

但是现在您遇到了不得不在另一个时刻关闭菜单的问题。

在这种情况下,当我需要一个类似 aContextMenu但不是默认行为的菜单时,我倾向于选择Popup.

用 a 说同样的话Popup

<StackPanel>
  <Button x:Name="button"
          Content="Button" />
  <Button x:Name="button2"
          Content="Button 2" />
  <Popup Placement="Right"
          PlacementTarget="{Binding ElementName=button}">
    <Menu>
      <MenuItem Header="AAA" />
    </Menu>
    <Popup.Style>
      <Style TargetType="{x:Type Popup}">
        <Setter Property="IsOpen"
                Value="True" />
        <Style.Triggers>
          <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
              <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                            Path=PlacementTarget.IsMouseOver}"
                          Value="False" />
              <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                            Path=IsMouseOver}"
                          Value="False" />
            </MultiDataTrigger.Conditions>
            <Setter Property="IsOpen"
                    Value="False" />
          </MultiDataTrigger>
        </Style.Triggers>
      </Style>
    </Popup.Style>
  </Popup>
</StackPanel>

您可以根据需要调整其条件。

于 2013-07-03T16:40:25.860 回答
0

我最近遇到了这个问题,当鼠标悬停在按钮上时,我需要一个菜单​​来打开和关闭。Viv 的出色答案(https://stackoverflow.com/a/17453601/3403999)有一个小警告:当鼠标从按钮转换到弹出窗口时(反之亦然),我注意到闪烁效果。基本上,弹出窗口会在那几分之一秒内关闭并重新打开。我最初尝试使用 Horizo​​ntalOffset 属性使弹出窗口重叠,但闪烁仍然存在。

我的最终解决方案是使用一个非常基本的故事板添加进入/退出操作,我想我会分享它,以防其他人看到 Viv 的答案并试图弄清楚如何防止闪烁:

<StackPanel>
    <Button x:Name="button"
            Content="Button" />
    <Button x:Name="button2"
            Content="Button 2" />
    <Popup Placement="Right"
           PlacementTarget="{Binding ElementName=button}">
        <Menu>
            <MenuItem Header="AAA" />
        </Menu>
        <Popup.Style>
            <Style TargetType="{x:Type Popup}">
                <Setter Property="IsOpen"
                        Value="True" />
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                                         Path=PlacementTarget.IsMouseOver}"
                                       Value="False" />
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                                         Path=IsMouseOver}"
                                       Value="False" />
                        </MultiDataTrigger.Conditions>
                        <MultiDataTrigger.EnterActions>
                            <BeginStoryboard x:Name="HidePopupStoryboard">
                                <Storyboard>
                                    <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen"
                                                                    Duration="0:0:0.1">
                                        <DiscreteBooleanKeyFrame KeyTime="100%"
                                                                 Value="False" />
                                    </BooleanAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiDataTrigger.EnterActions>
                        <MultiDataTrigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="HidePopupStoryboard" />
                        </MultiDataTrigger.ExitActions>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Popup.Style>
    </Popup>
</StackPanel>

您可以增加持续时间以使其持续打开一小段时间,但即使是 1/10 秒的延迟也足以防止我闪烁。你甚至可以加入一个双重动画,让它淡出/淡入,而不是直接打开/关闭。

于 2019-06-25T13:55:02.257 回答