WPF MenuItem自定义子项hover效果异常,仅需子MenuItem高亮求助
问题
我有一个包含多个MenuItem的上下文菜单,其中名为“In Postfach kopieren”的MenuItem原本有大量子MenuItem。因为子项数量有时过多,我给它实现了滚动条与搜索功能:将Grid作为该MenuItem的子项,Grid包含三个元素:
- 文本标签
- 用于输入搜索文本的TextBox
- 内部嵌套StackPanel的ScrollViewer(StackPanel中是用户列表MenuItem)
功能运行正常,但鼠标悬停在“In Postfach kopieren”弹出的内容区域时,整个控件会高亮,我只希望列表中的MenuItem触发高亮效果。尝试通过Grid、StackPanel等控件的鼠标进入事件禁用该效果,但没有成功。
代码如下:
var cbtnPostfachKopieren = new System.Windows.Controls.MenuItem(); cbtnPostfachKopieren.Header = "In Postfach kopieren"; cbtnPostfachKopieren.Items.Clear(); var grid = new Grid(); grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(150) }); grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto }); grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto }); var textBlock = new TextBlock(); textBlock.Text = "Search"; Grid.SetRow(textBlock, 0); Grid.SetColumn(textBlock, 0); grid.Children.Add(textBlock); var textBox = new System.Windows.Controls.TextBox(); textBox.TextChanged += TextBox_TextChanged; textBox.Width = 150; textBox.Margin = new Thickness(10, 0, 0, 0); textBox.Text = "Abishek"; Grid.SetRow(textBox, 0); Grid.SetColumn(textBox, 1); grid.Children.Add(textBox); cbtnPostfachKopieren.Items.Add(grid); var scrollViewer = new ScrollViewer { VerticalScrollBarVisibility = ScrollBarVisibility.Visible, Height = 100, HorizontalAlignment = HorizontalAlignment.Right }; scrollViewer.Foreground = Brushes.Brown; Grid.SetRow(scrollViewer, 1); Grid.SetColumn(scrollViewer, 0); Grid.SetColumnSpan(scrollViewer, 2); grid.Children.Add(scrollViewer); var stackpanel = new StackPanel(); scrollViewer.Content = stackpanel; for (int i = 0; i < 5; i++) { System.Windows.Controls.MenuItem _btnInPostfachKopierenUserInfo = new System.Windows.Controls.MenuItem(); _btnInPostfachKopierenUserInfo.Header = "Abishek Kumar JAin Ravikumar"; stackpanel.Children.Add(_btnInPostfachKopierenUserInfo); _btnInPostfachKopierenUserInfo.Click += _btnInPostfachKopierenUserInfo_Click; }
解决方案
问题根源是MenuItem的容器模板会对整个子内容区域应用高亮样式,可通过以下两种方法解决:
方法一:自定义容器样式,仅让列表MenuItem触发高亮
通过修改MenuItem的ItemContainerStyle,限制高亮效果仅作用于用户列表中的子MenuItem:
首先在XAML中定义样式:
<Style x:Key="CustomMenuItemContainerStyle" TargetType="{x:Type MenuItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type MenuItem}"> <Border x:Name="Border" Background="Transparent" BorderBrush="Transparent" BorderThickness="1"> <ContentPresenter x:Name="ContentPresenter" ContentSource="Header" Margin="2" RecognizesAccessKey="True"/> </Border> <ControlTemplate.Triggers> <!-- 仅当当前项无嵌套子项时,鼠标悬停才显示高亮 --> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}" Value="0"> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="Background" Value="#FFE1F5FE"/> <Setter TargetName="Border" Property="BorderBrush" Value="#FF7EB4EA"/> </Trigger> </DataTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
然后在代码中给父MenuItem应用该样式:
cbtnPostfachKopieren.ItemContainerStyle = (Style)FindResource("CustomMenuItemContainerStyle");
方法二:禁用容器的鼠标命中测试,仅保留必要控件的交互性
通过设置Grid的IsHitTestVisible为False,阻止它触发父MenuItem的高亮,同时单独开启TextBox和列表MenuItem的命中测试:
// 禁止Grid接收鼠标事件,避免触发父项高亮 grid.IsHitTestVisible = false; // 确保TextBox可正常交互 textBox.IsHitTestVisible = true; // 确保每个用户列表项可响应鼠标悬停和点击 foreach (var menuItem in stackpanel.Children.OfType<MenuItem>()) { menuItem.IsHitTestVisible = true; }
这种方法更简洁,直接通过事件拦截实现需求。
内容的提问来源于stack exchange,提问作者abishekgolecha
相关产品推荐
相关产品推荐

