在 WPF 应用程序中打开或关闭 ContextMenu 时调整按钮的视觉状态

Adjusting the visual state of a button when ContextMenu is open or closed in WPF app

在我正在开发的 WPF 应用程序中,有一个 Button Style 定义了它自己的 Template (ControlTemplate).

我通过 ControlTemplate.Triggers 处理视觉更新,例如 IsMouseOver 的以下内容:

<Trigger Property="IsMouseOver" Value="True">
  <Trigger.EnterActions>
      <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation 
              Storyboard.TargetName="IsMouseOverBorder" 
              Storyboard.TargetProperty="Opacity" 
              To="1" 
              Duration="0:0:0.08" />
          </Storyboard>
      </BeginStoryboard>
  </Trigger.EnterActions>
  <Trigger.ExitActions>
      <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation 
              Storyboard.TargetName="IsMouseOverBorder" 
              Storyboard.TargetProperty="Opacity" 
              To="0" 
              Duration="0:0:0.16" />
          </Storyboard>
      </BeginStoryboard>
  </Trigger.ExitActions>
</Trigger>

我已经为一些使用这种风格的 Button 添加了上下文菜单。这样做之后,当右键单击 Button 时,会显示上下文菜单,但 IsMouseOver 触发器会立即执行退出操作。我更希望在上下文菜单打开时保持 IsMouseOver 视觉状态——这样看起来会好得多。

我该怎么做?

这里有几个额外的触发器,我认为它们可以实现我想要的,但事实并非如此。第一个触发器 (ContextMenuOpening) 起作用,但第二个触发器不起作用 - 按钮处于永久 IsMouseOver 外观状态。

<EventTrigger RoutedEvent="ContextMenuService.ContextMenuOpening">
  <BeginStoryboard Name="ContextMenuOpeningStoryboard">
    <Storyboard>
      <DoubleAnimation 
        Storyboard.TargetName="IsMouseOverBorder" 
        Storyboard.TargetProperty="Opacity" 
        To="1" 
        Duration="0" />
    </Storyboard>
  </BeginStoryboard>
</EventTrigger>

<EventTrigger RoutedEvent="ContextMenuService.ContextMenuClosing">
  <RemoveStoryboard BeginStoryboardName="ContextMenuOpeningStoryboard" />
</EventTrigger>

知道为什么这行不通,或者有其他可行的方法吗?

我使用我的问题中定义的样式让它工作,但我不得不手动引发 ContextMenuService.ContextMenuClosingEvent 事件(使用一些反射来这样做):

<ContextMenu Closed="ContextMenu_Closed">...</ContextMenu>

后面的代码:

private void ContextMenu_Closed(object sender, RoutedEventArgs args)
{

  var type = typeof(ContextMenuEventArgs);

  var contextMenuEventArgs = (ContextMenuEventArgs) type.Assembly.CreateInstance
  (
    type.FullName, false, BindingFlags.Instance | BindingFlags.NonPublic, null, 
    new object[] { this, false }, null, null
  );

  if (contextMenuEventArgs != null) 
  {
    contextMenuEventArgs.RoutedEvent = ContextMenuService.ContextMenuClosingEvent;
    _myToggleButton.RaiseEvent(contextMenuEventArgs);
  }

}