C# WPF将鼠标滚轮事件从上下文菜单发送到窗口

C# WPF将鼠标滚轮事件从上下文菜单发送到窗口,c#,wpf,contextmenu,contextmenustrip,C#,Wpf,Contextmenu,Contextmenustrip,我有一个窗口,上面有一个按钮。该按钮具有关联菜单: <Window> <ScrollViewer Height="500"> <Button Height = "2000"> <Button.ContextMenu> <ContextMenu> <MenuItem Header="Item1"></MenuItem> <MenuItem Header="Item2"&

我有一个窗口,上面有一个按钮。该按钮具有关联菜单:

<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 form应用程序中,我有同样的问题,但我可以通过使用ContextMenuStrip替换ContextMenuStrip来解决。在WPF中,看起来没有上下文菜单提示。

除了使用
上下文菜单
,您可以使用一个看起来像
上下文菜单
弹出窗口

<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>


如果要使用
SystemDropShadowChrome
,,请记住添加对
PresentationFramework.Aero2.dll的引用不幸的是,上下文菜单弹出窗口在WPF逻辑树中不是其主机的祖先。这意味着从上下文菜单到scrollviewer的事件冒泡不起作用,因此scrollviewer不会收到任何鼠标滚轮活动的通知

但是,如果您只想在scrollviewer中向上/向下滚动,您可以通过监听上下文菜单上的鼠标滚轮事件,然后手动滚动scrollviewer,非常轻松地复制自己的行为

例如,xaml:


在视图的代码隐藏中,您可以执行以下类似操作:

public主窗口()
{
初始化组件();
this.MyContextMenu.MouseWheel+=OnContextMenuMouseWheel;
}
私有void OnContextMenuMouseWheel(对象发送方,MouseWheelEventArgs e)
{
var currentOffset=MyScrollViewer.VerticalOffset;
var newOffset=当前偏移量-e.增量;
MyScrollViewer.ScrollToVerticalOffset(newOffset);
e、 已处理=正确;
}

它看起来很简单,可以滚动。但是,在我的例子中,代码中的按钮是一个自定义控件。它将被添加到我不知道的地方。强迫使用我的自定义控件的人自己处理MouseWheel事件或向我的自定义控件提供MyScrollViewer都是奇怪的解决方案。事实上,在我的项目中,我们自定义了很多默认的上下文菜单。我已经尝试改变我们的自定义上下文菜单继承从弹出窗口而不是上下文菜单,但有很多事情也应该改变。但是正如约翰在上面所描述的,我认为你的解决方案是最好的方法。