簡體   English   中英

WPF DataGrid:單擊鼠標左鍵顯示動態上下文菜單

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM