WPF将鼠标滚轮事件从ContextMenu发送到窗口

问题描述 投票:-1回答:2

我有一个窗户,上面有一个按钮。该按钮具有上下文菜单:

<Window>
 <ScrollViewer Height="500">
  <Button Height = "2000">
   <Button.ContextMenu>
    <ContextMenu>
     <MenuItem Header="Item1"></MenuItem>
     <MenuItem Header="Item2"></MenuItem>
     <MenuItem Header="Item3"></MenuItem>
    </ContextMenu>
   </Button.ContextMenu>
  </Button>
 </ScrollViewer>
</Window>

[只要我右键单击按钮,就会显示上下文菜单。当我将鼠标移出上下文菜单并滚动滚轮时,scrollViewer根本不会滚动。我已经尝试了许多关于鼠标离开或鼠标进入事件的方法,但是没有任何帮助。我希望上下文菜单仍然显示,但是将转轮事件发送到scrollViewer(或窗口),如果我在上下文菜单之外单击,它将正常关闭。

在win窗体应用程序中,我有相同的问题,但是我可以通过使用ContextMenuStrip替代ContextMenu来解决。在WPF中,看起来像没有ContextMenuStrip。

c# wpf contextmenu contextmenustrip
2个回答
0
投票
使用ContextMenu的理解,您可以使用看起来像PopupContextMenu

<ScrollViewer Height="500"> <Button Height="2000"> <Popup x:Name="popup" Placement="Mouse" StaysOpen="False" xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2"> <theme:SystemDropShadowChrome Name="Shdw" Color="Transparent" SnapsToDevicePixels="true"> <Border Name="ContextMenuBorder" Background="#F5F5F5" BorderBrush="#FF959595" BorderThickness="1" SnapsToDevicePixels="True"> <ScrollViewer Name="ContextMenuScrollViewer" Grid.ColumnSpan="2" Margin="1,0" Style="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type FrameworkElement}, ResourceId=MenuScrollViewer}}"> <Grid RenderOptions.ClearTypeHint="Enabled"> <Canvas Height="0" Width="0" HorizontalAlignment="Left" VerticalAlignment="Top"> <Rectangle Name="OpaqueRect" Height="{Binding ElementName=ContextMenuBorder, Path=ActualHeight}" Width="{Binding ElementName=ContextMenuBorder, Path=ActualWidth}" Fill="{Binding ElementName=ContextMenuBorder, Path=Background}" SnapsToDevicePixels="True"/> </Canvas> <Rectangle Fill="#F1F1F1" HorizontalAlignment="Left" Width="28" Margin="1,2" RadiusX="2" RadiusY="2" SnapsToDevicePixels="True"/> <Rectangle HorizontalAlignment="Left" Width="1" Margin="29,2,0,2" Fill="#E2E3E3" SnapsToDevicePixels="True"/> <Rectangle HorizontalAlignment="Left" Width="1" Margin="30,2,0,2" Fill="White" SnapsToDevicePixels="True"/> <StackPanel> <MenuItem Header="Item1"></MenuItem> <MenuItem Header="Item2"></MenuItem> <MenuItem Header="Item3"></MenuItem> </StackPanel> </Grid> </ScrollViewer> </Border> </theme:SystemDropShadowChrome> </Popup> <Button.Triggers> <EventTrigger RoutedEvent="MouseRightButtonUp"> <BeginStoryboard> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetName="popup" Storyboard.TargetProperty="IsOpen"> <DiscreteBooleanKeyFrame KeyTime="00:00:00.1" Value="True"/> </BooleanAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Button.Triggers> </Button> </ScrollViewer>

如果要使用PresentationFramework.Aero2.dll,请记住添加对SystemDropShadowChrome的引用。 

不幸的是,当涉及到WPF逻辑树时,上下文菜单弹出窗口并不是其主机的祖先。这意味着从上下文菜单到scrollviewer的事件冒泡不起作用,因此不会向scrollviewer通知任何鼠标滚轮活动。

但是,如果您只想在scrollviewer中向上/向下滚动,则可以通过侦听上下文菜单上的MouseWheel事件然后手动滚动ScrollViewer来轻松复制自己的行为。

例如xaml:

<ScrollViewer Height="500" x:Name="MyScrollViewer"> <Button Height = "2000"> <Button.ContextMenu> <ContextMenu x:Name="MyContextMenu"> <MenuItem Header="Item1"></MenuItem> <MenuItem Header="Item2"></MenuItem> <MenuItem Header="Item3"></MenuItem> </ContextMenu> </Button.ContextMenu> </Button> </ScrollViewer>

在您后面的代码中,您可以执行以下操作:

public MainWindow() { InitializeComponent(); this.MyContextMenu.MouseWheel += OnContextMenuMouseWheel; } private void OnContextMenuMouseWheel(object sender, MouseWheelEventArgs e) { var currentOffset = MyScrollViewer.VerticalOffset; var newOffset = currentOffset - e.Delta; MyScrollViewer.ScrollToVerticalOffset(newOffset); e.Handled = true; }


1
投票
不幸的是,当涉及到WPF逻辑树时,上下文菜单弹出窗口并不是其主机的祖先。这意味着从上下文菜单到scrollviewer的事件冒泡不起作用,因此不会向scrollviewer通知任何鼠标滚轮活动。
© www.soinside.com 2019 - 2024. All rights reserved.