WPF ContextMenu 吞下所有鼠标事件
WPF ContextMenu swallowing all mouse events
我发现了一个错误,但我不明白为什么会这样。
我有数据网格。在鼠标左键上单击我想打开上下文菜单。
我做到了。它工作正常,直到我开始随机单击 DataGrid 的单元格(每次 ContextMenu 关闭并重新出现在新位置)。但是有一刻发生了一些事情,更新的 ContextMenu 显示(并且 Window 不响应任何鼠标事件,例如单击按钮等)......直到我将光标移出 window 和 return 它(或单击 Alt 或 F10)。
这里是一些代码:
上下文菜单(在 <DataGrid.Resources>
内)
<ContextMenu Style="{StaticResource DefaultContextMenuStyle}" x:Key="cm"
DataContext="{Binding Data, Source={StaticResource WindowViewModel}}">
</ContextMenu>
DataGrid 列:
<DataGridTemplateColumn Header="TestHeader" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel ContextMenu="{StaticResource cm}" VerticalAlignment="Stretch" Background="Transparent">
<i:Interaction.Behaviors>
<local:OpenContextMenuLeftBehavior />
</i:Interaction.Behaviors>
<TextBlock Style="{StaticResource TextVCenteredCellStyle}" Text="{Binding LPU}" />
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
以及打开上下文菜单的行为:
public class OpenContextMenuLeftBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.PreviewMouseUp += OpenContextMenu;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseUp -= OpenContextMenu;
}
void OpenContextMenu(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left) {
FrameworkElement Sender = sender as FrameworkElement;
Sender.ContextMenu.PlacementTarget = Sender;
Sender.ContextMenu.IsOpen = true;
}
}
}
当我发现该错误时,我尝试使用 Snoop WPF 查找一些信息。
这里有一些信息:
在坏事发生之前,单击单元格就像:
before bad thing
坏事后:
after bad thing
第一个事件发生在 Popup(上下文菜单部分?),它不属于 window VisualTree。当我将鼠标移出它时,这个弹出窗口似乎遍及整个 Window 并关闭。
所以,我在那个错误上浪费了 2 天时间,这就是我能找到的全部。
请帮助我。
编辑:
我创建了最小示例:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="dg1" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<i:Interaction.Behaviors>
<local:OpenContextMenuLeftBehavior />
</i:Interaction.Behaviors>
<DockPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="123456"></MenuItem>
</ContextMenu>
</DockPanel.ContextMenu>
<TextBlock Text="123" />
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
后面的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
dg1.ItemsSource = new List<int>()
{
1,2,3,4,5,6,7,8,9,0
};
}
}
public class OpenContextMenuLeftBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.PreviewMouseUp += OpenContextMenu;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseUp -= OpenContextMenu;
}
void OpenContextMenu(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left) {
FrameworkElement Sender = sender as FrameworkElement;
if (Sender != null) {
Sender.ContextMenu.PlacementTarget = Sender;
Sender.ContextMenu.IsOpen = true;
Sender.ContextMenu.UpdateLayout();
}
}
}
}
要重现此错误,只需快速单击不同的单元格
修改后的答案
在您发布完整、简单的示例后,我建议如下:
创建 ContextMenu
之后
Sender.ContextMenu.IsOpen = true;
Sender.ContextMenu.PreviewMouseUp += ContextMenu_PreviewMouseUp;
已定义
private void ContextMenu_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
var Sender = (sender as ContextMenu);
if (Sender != null)
{
Sender.IsOpen = true;
e.Handled = true;
}
}
(您仍然需要管理网格线选择,但这里就像题外话一样)
我发现了一个错误,但我不明白为什么会这样。 我有数据网格。在鼠标左键上单击我想打开上下文菜单。 我做到了。它工作正常,直到我开始随机单击 DataGrid 的单元格(每次 ContextMenu 关闭并重新出现在新位置)。但是有一刻发生了一些事情,更新的 ContextMenu 显示(并且 Window 不响应任何鼠标事件,例如单击按钮等)......直到我将光标移出 window 和 return 它(或单击 Alt 或 F10)。
这里是一些代码:
上下文菜单(在 <DataGrid.Resources>
内)
<ContextMenu Style="{StaticResource DefaultContextMenuStyle}" x:Key="cm"
DataContext="{Binding Data, Source={StaticResource WindowViewModel}}">
</ContextMenu>
DataGrid 列:
<DataGridTemplateColumn Header="TestHeader" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel ContextMenu="{StaticResource cm}" VerticalAlignment="Stretch" Background="Transparent">
<i:Interaction.Behaviors>
<local:OpenContextMenuLeftBehavior />
</i:Interaction.Behaviors>
<TextBlock Style="{StaticResource TextVCenteredCellStyle}" Text="{Binding LPU}" />
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
以及打开上下文菜单的行为:
public class OpenContextMenuLeftBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.PreviewMouseUp += OpenContextMenu;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseUp -= OpenContextMenu;
}
void OpenContextMenu(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left) {
FrameworkElement Sender = sender as FrameworkElement;
Sender.ContextMenu.PlacementTarget = Sender;
Sender.ContextMenu.IsOpen = true;
}
}
}
当我发现该错误时,我尝试使用 Snoop WPF 查找一些信息。 这里有一些信息:
在坏事发生之前,单击单元格就像:
before bad thing坏事后:
after bad thing
第一个事件发生在 Popup(上下文菜单部分?),它不属于 window VisualTree。当我将鼠标移出它时,这个弹出窗口似乎遍及整个 Window 并关闭。
所以,我在那个错误上浪费了 2 天时间,这就是我能找到的全部。
请帮助我。
编辑: 我创建了最小示例:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="dg1" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<i:Interaction.Behaviors>
<local:OpenContextMenuLeftBehavior />
</i:Interaction.Behaviors>
<DockPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="123456"></MenuItem>
</ContextMenu>
</DockPanel.ContextMenu>
<TextBlock Text="123" />
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
后面的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
dg1.ItemsSource = new List<int>()
{
1,2,3,4,5,6,7,8,9,0
};
}
}
public class OpenContextMenuLeftBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.PreviewMouseUp += OpenContextMenu;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseUp -= OpenContextMenu;
}
void OpenContextMenu(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left) {
FrameworkElement Sender = sender as FrameworkElement;
if (Sender != null) {
Sender.ContextMenu.PlacementTarget = Sender;
Sender.ContextMenu.IsOpen = true;
Sender.ContextMenu.UpdateLayout();
}
}
}
}
要重现此错误,只需快速单击不同的单元格
修改后的答案
在您发布完整、简单的示例后,我建议如下: 创建 ContextMenu
之后 Sender.ContextMenu.IsOpen = true;
Sender.ContextMenu.PreviewMouseUp += ContextMenu_PreviewMouseUp;
已定义
private void ContextMenu_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
var Sender = (sender as ContextMenu);
if (Sender != null)
{
Sender.IsOpen = true;
e.Handled = true;
}
}
(您仍然需要管理网格线选择,但这里就像题外话一样)