Из Apple Docs ;
. Примечание
. Монитор
blockquote>Block
вызывается для всех будущих событий, соответствующих маске. Вы должны позвонитьremoveMonitor(_:)
, чтобы остановить монитор. При сборке мусора монитор (и все, что ссылается на Блок) не будет собираться до тех пор, пока не будет вызванremoveMonitor(_:)
.Это означает, что монитор будет продолжать поиск совпадающих событий, пока не будет вызвано
removeMonitor()
. Таким образом, ваша система использует дополнительную память для продолжения поиска событий, и если вы никогда не вызовете это - это может привести к довольно большой утечке памяти. Как говорится даже при сборке мусора, этот объект все еще выделяется - потому что он ищет события, которые могут произойти в любое время (поэтому не гарантируется, что он будет собран). Обязательно звоните, когда хотите, чтобы система перестала искать события.Вы также можете сделать что-то подобное в вашем
handler
.Вы можете вернуть событие без изменения, создать и вернуть новый объект NSEvent или вернуть nil, чтобы остановить отправку события.
BLOCKQUOTE>
Единственный способ, который я мог найти, чтобы даже приблизиться к генерации этого поведения, это создать меню в переполнении, которое содержало бы один пункт меню, заголовок которого сам по себе был другим пунктом меню, называемым «Специальные элементы» и содержащий надлежащие дочерние элементы. Это работало как задумано, но выглядело странно (это можно исправить с помощью пользовательских шаблонов), а также выглядит как огромный взлом. Единственный «правильный» способ сделать это, о котором я могу подумать, - это создать собственный элемент управления, подобный MenuItem, который при наведении вызывает всплывающее окно ContextMenu или Popup, поскольку я не думаю, что пользовательский ControlTemplate может изменить поведение по умолчанию меню, чтобы не требовать щелчка по элементу верхнего уровня.
Another solution is to use the existing templates and override the Template for the TopLevelHeader with the Template of the SubmenuHeader.
<Style x:Key="MenuItemStyle" TargetType="{x:Type MenuItem}">
<Style.Triggers>
<Trigger Property="Role" Value="TopLevelHeader">
<Setter Property="Template"
Value="{StaticResource {x:Static MenuItem.SubmenuHeaderTemplateKey}}"/>
</Trigger>
</Style.Triggers>
</Style>
And use this style in your top level MenuItem. That should simplify your code.
EDIT: You're right, it only works when you click on it (don't know how I convinced myself it worked, sorry :)). It's functionality is like a TopLevelMenu even though the Template says otherwise, its quite confusing.
Only thing I can think of is adding a Trigger to show the Submenu on IsMenuOver and handling the Click event so it does nothing but I don't know how well that would work.
После дополнительного чтения я использую решение ниже.
<!-- Resource Dictionary Stuff -->
<!-- Some Brushes -->
<SolidColorBrush x:Key="Brush_1"
Color="White" />
<LinearGradientBrush x:Key="Brush_2"
StartPoint="0 0"
EndPoint="0 1">
<GradientStop
Color="White"
Offset="0"/>
<GradientStop
Color="DarkSeaGreen"
Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="Brush_3"
Color="DarkOliveGreen"/>
<!-- Custom MenuItem - Top Level Header - Style 1 -->
<Style x:Key="MenuItem_TLH_Style1"
TargetType="MenuItem">
<!--<EventSetter Event="PreviewMouseDown" Handler="DoNothing"/>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Name="ControlTemplate"
TargetType="MenuItem">
<!-- A headered text that may display a submenu
on a trigger. This submenu is the host for a
menu item's items. -->
<Border x:Name="BoundaryBorder"
Background="{StaticResource Brush_1}"
BorderThickness="1">
<Grid x:Name="ContainerGrid">
<ContentPresenter x:Name="HeaderContent"
Margin="6 3 6 3"
ContentSource="Header"
RecognizesAccessKey="True"/>
<Popup x:Name="SubmenuPopup"
Placement="Bottom"
IsOpen="{TemplateBinding IsSubmenuOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Fade">
<Border x:Name="SubmenuBoundaryBorder"
SnapsToDevicePixels="True"
Background="{StaticResource Brush_1}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1">
<StackPanel x:Name="ItemsStackPanel"
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle"/>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!-- -->
<Trigger
Property="IsSuspendingPopupAnimation"
Value="true">
<Setter
TargetName="SubmenuPopup"
Property="PopupAnimation"
Value="Fade"/>
</Trigger>
<!-- On mouse-over, show the submenu and highlight the header. -->
<Trigger
Property="IsMouseOver"
Value="true">
<Setter
TargetName="BoundaryBorder"
Property="Background"
Value="{StaticResource Brush_2}"/>
<Setter
TargetName="BoundaryBorder"
Property="BorderBrush"
Value="{StaticResource Brush_3}"/>
<Setter
Property="IsSubmenuOpen"
Value="true"/>
<!-- sloppy? -->
<Setter
TargetName="SubmenuPopup"
Property="IsOpen"
Value="true"/>
</Trigger>
<Trigger
SourceName="SubmenuPopup"
Property="AllowsTransparency"
Value="true">
<Setter
TargetName="SubmenuBoundaryBorder"
Property="CornerRadius"
Value="0 0 4 4"/>
<Setter
TargetName="SubmenuBoundaryBorder"
Property="Padding"
Value="0 0 0 3"/>
</Trigger>
<!-- Visually indicate an unaccessible menu item. -->
<Trigger
Property="IsEnabled"
Value="false">
<Setter
Property="Foreground"
Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ... -->
<!-- Inside a window XAML file -->
<!-- Tool Bar Tray -->
<ToolBarTray x:Name="toolBarTray1"
DockPanel.Dock="Top">
<!-- File And Edit Tools -->
<ToolBar x:Name="toolBar1"
Band="1" BandIndex="1">
<!-- Displayed Buttons -->
<Button x:Name="ButtonA"
Content="A"/>
<Button x:Name="ButtonB"
Content="B"/>
<!-- Overflow Menu For Special Items -->
<Menu x:Name="OverflowMenu"
ToolBar.OverflowMode="Always">
<MenuItem x:Name="SpecialsMenuItem"
Style="{StaticResource MyStyle}"
Header="Special Items">
<MenuItem x:Name="CMenuItem"
Header="C">
<MenuItem x:Name="DMenuItem"
Header="D"/>
</MenuItem>
</MenuItem>
</Menu>
</ToolBar>
</ToolBarTray>
Я атакую поведение SubmenuPopup на наведением мыши, а не обработкой события click. Я хотел бы понять это более полно, поэтому я попытался закомментировать эту часть триггера и добавить обработчик события, который вызывает метод DoNothing () для события PreviewMouseDown. Оказывается, я что-то упускаю и думаю, что это связано с фокусировкой и / или с тем, как меню обрабатывает свою коллекцию элементов. Отсутствие возможности распространения события после «DoNothing ()» (routedEventArgs.Handled = true), по-видимому, устраняет проблемы при нажатии на пункт меню «Специальные элементы». Однако, если кто-то вышел из меню или добавил другой пункт меню, а затем щелкнул по нему, поведение при наведении может быть выключено или включено и выключено.