[英]WPF DataGrid: Show dynamic context menu on left click
當我在DataGrid中單擊一個單元格時,我會不時顯示一個上下文菜單。 我以編程方式創建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無效?
關於第一個解決方案。
使用MouseDown事件時會出現一些問題,因為該事件可能被標記為由其他控件處理。 PreviewMouseDown是一個預覽事件,沒有標記,因此在使用它時,它會從根元素和控件一直到實現。
有關更多信息,您可以在這里閱讀: MSDN UIElement.MouseDown事件
為DataGrid
定義一個空的ContextMenu
。
<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);
}
最好是像這樣<DataGrid ... DataGridCell.PreviewMouseDown="DataGridCell_MouseDown" ... />
這樣在DataGrid
級別處理PreviewMouseDown event
。
這樣,您將ContextMenu
作為ContextMenu ctxmenu = (sender as DataGrid).ContextMenu;
。 如果您想做一些初步的准備,最好使用預覽事件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.