WPF 将鼠标滚轮事件从 ContextMenu 发送到 Window
WPF sending mouse wheel event from ContextMenu to Window
我有一个 window,上面有一个按钮。该按钮有一个上下文菜单:
<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(或 window),如果我在上下文菜单外单击,它将正常关闭。
在 win-form 应用程序中,我有同样的问题,但我可以通过使用 ContextMenuStrip 代替 ContextMenu 来解决它。在 WPF 中,看起来没有 ContextMenuStrip。
您可以使用看起来像 ContextMenu
:
的 Popup
而不是使用 ContextMenu
<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 逻辑树时,上下文菜单弹出窗口并不是其宿主的祖先。这意味着从上下文菜单到滚动查看器的事件冒泡不起作用,因此滚动查看器不会收到任何鼠标滚轮的通知 activity.
但是,如果您只想在滚动查看器中滚动 up/down,您可以通过在上下文菜单上侦听 MouseWheel 事件然后手动滚动滚动查看器来非常轻松地自己复制行为。
例如。 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;
}
我有一个 window,上面有一个按钮。该按钮有一个上下文菜单:
<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(或 window),如果我在上下文菜单外单击,它将正常关闭。
在 win-form 应用程序中,我有同样的问题,但我可以通过使用 ContextMenuStrip 代替 ContextMenu 来解决它。在 WPF 中,看起来没有 ContextMenuStrip。
您可以使用看起来像 ContextMenu
:
Popup
而不是使用 ContextMenu
<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 逻辑树时,上下文菜单弹出窗口并不是其宿主的祖先。这意味着从上下文菜单到滚动查看器的事件冒泡不起作用,因此滚动查看器不会收到任何鼠标滚轮的通知 activity.
但是,如果您只想在滚动查看器中滚动 up/down,您可以通过在上下文菜单上侦听 MouseWheel 事件然后手动滚动滚动查看器来非常轻松地自己复制行为。
例如。 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;
}