有时我想在DataGrid中单击一个Cell时显示一个上下文菜单。 我以编程方式创建ContextMenu,然后使用ContextMenu.IsOpen = true显示它。在下面的示例中,它在“网格”面板内部单击时起作用,但它不会,单击DataGrid中的单元格(单元格内的UIElement)。
那有什么区别?我还需要做些什么才能使它在DataGridCell上运行?
这是一个演示版本,第一个是XAML,后面是代码。
<Window x:Class="WpfApplication7_delete_me.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication7_delete_me"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid MouseDown="Grid_MouseDown" Background="Beige">
<DataGrid x:Name="dataGrid" HorizontalAlignment="Left" VerticalAlignment="Top" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" MouseDown="TextBlock_MouseDown" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
后面是代码:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication7_delete_me {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
Person p1 = new Person(); p1.Name = "abc";
Person p2 = new Person(); p2.Name = "1q23";
List<Person> l = new List<Person>() { p1, p2 };
dataGrid.ItemsSource = l;
}
private void Grid_MouseDown(object sender, MouseButtonEventArgs e) {
ContextMenu cm = new ContextMenu();
MenuItem mi = new MenuItem();
mi.Header = "hallo";
cm.Items.Add(mi);
cm.IsOpen = true;
}
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e) {
ContextMenu cm = new ContextMenu();
MenuItem mi = new MenuItem();
mi.Header = "hallo";
cm.Items.Add(mi);
cm.IsOpen = true;
}
}
class Person {
public string Name { get; set; }
}
}
一段时间后,我找到了两个解决方案:
1)使用PreviewMouseDown而不是MouseDown时它正在工作。
2)使用:Dispatcher.BeginInvoke(new Action(() => { c.IsOpen = true; }), null);
但为什么在MouseDown事件中设置IsOpen不起作用?
答案 0 :(得分:0)
关于第一个解决方案。
使用MouseDown事件时存在一些问题,因为事件可能被标记为由其他控件处理。 PreviewMouseDown是一个预览事件,它没有被标记,因此当你使用它时,它会从根元素和控件一直到你的实现。
有关详细信息,请参阅此处:MSDN UIElement.MouseDown Event
答案 1 :(得分:0)
为ContextMenu
定义一个空的DataGrid
。
<DataGrid.ContextMenu>
<ContextMenu x:Name="CtxMenu">
</ContextMenu>
</DataGrid.ContextMenu>
处理ContextMenuOpening
事件:
private void DataGrid_ContextMenuOpening_1(object sender, ContextMenuEventArgs e)
{
ContextMenu ctxmenu = (sender as DataGrid).ContextMenu;
// suppress ContextMenu if empty
e.Handled = ctxmenu.Items.Count == 0;
}
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
ContextMenu ctxmenu = Dgrd.ContextMenu;
MenuItem mi = new MenuItem();
mi.Header = "hallo";
ctxmenu.Items.Add(mi);
}
最好在PreviewMouseDown event
级别DataGrid
处理<DataGrid ... DataGridCell.PreviewMouseDown="DataGridCell_MouseDown" ... />
。
通过这种方式,ContextMenu
为ContextMenu ctxmenu = (sender as DataGrid).ContextMenu;
。如果您想进行初步准备,也可以使用预览事件。