【问题标题】:WPF sending mouse wheel event from ContextMenu to WindowWPF 将鼠标滚轮事件从 ContextMenu 发送到 Window
【发布时间】:2019-12-14 06:37:45
【问题描述】:

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

<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 作为 ContextMenu 的替代品来解决它。在 WPF 中,看起来没有 ContextMenuStrip。

【问题讨论】:

    标签: c# wpf contextmenu contextmenustrip


    【解决方案1】:

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

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

    例如。 xml:

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

    【讨论】:

    • 它看起来很简单,可以滚动。但是,就我而言,代码中的按钮是自定义控件。它将被添加到我不知道的地方。强迫使用我的自定义控件的人自己处理 MouseWheel 事件或向我的自定义控件提供 MyScrollViewer 都是奇怪的解决方案。
    【解决方案2】:

    如果要使用ContextMenu,您可以使用看起来像ContextMenuPopup

    <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 的引用。

    【讨论】:

    • 其实在我的项目中,我们自定义了很多默认的ContextMenu。我尝试将我们的自定义 ContextMenu 更改为从 Popup 而不是 ContextMenu 继承,但也有很多事情应该改变。但正如上面约翰所描述的,我认为你的解决方案是最好的方法。
    猜你喜欢
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2014-08-04
    • 1970-01-01
    相关资源
    最近更新 更多