【问题标题】:WPF ContextMenu swallowing all mouse eventsWPF ContextMenu 吞下所有鼠标事件
【发布时间】:2016-08-31 17:52:09
【问题描述】:

我发现了一个错误,但我不明白为什么会这样。 我有数据网格。在鼠标左键单击我想打开 ContextMenu。 我做到了。它工作正常,直到我开始随机单击 DataGrid 的单元格(每次 ContextMenu 关闭并重新出现在新位置)。但是在某一时刻发生了一些事情并且 ContextMenu 更新显示(并且窗口不响应任何鼠标事件,例如单击按钮等)......直到我将光标移出窗口并返回它(或单击 Alt 或 F10) .

这里有一些代码:
ContextMenu(在<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>

以及打开 ContextMenu 的行为:

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 查找一些信息。 这里有一些信息:

  1. 在坏事发生之前,单击单元格就像:
    before bad thing

  2. 坏事后:
    after bad thing
    第一个事件发生在 Popup(ContextMenu 部分?),它不属于窗口 VisualTree。当我将鼠标移出时,此弹出窗口似乎遍布整个主窗口并关闭。

所以,我在那个错误上浪费了 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();
            }
        }
    }
}

要重现此错误,只需快速单击不同的单元格

【问题讨论】:

标签: c# wpf datagrid contextmenu


【解决方案1】:

修改后的答案

在您发布了一个完整、简单的示例后,我建议您执行以下操作: 创建 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;
        }
    }

(您仍然需要管理网格线的选择,但这里好像跑题了)

【讨论】:

  • 不,没有用。
  • @FrantsevM 已修订。也可以试试UpdateLayout
  • 真正无济于事的是,您没有分享一个完整的示例和一个清晰、确定性的步骤序列来重现您的问题。
  • 我添加了简单的例子。
  • @FrantsevM 谢谢,让我快速看一下,如果我可以复制问题...
猜你喜欢
  • 2013-06-29
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 2013-07-23
  • 2014-08-04
  • 1970-01-01
  • 2013-04-04
  • 2018-10-08
相关资源
最近更新 更多