2016-10-09 5 views
0

Время от времени я хотел бы показывать контекстное меню при нажатии на ячейку в DataGrid. Я создаю ContextMenu программно, а затем показываю его с помощью ContextMenu.IsOpen = true. В приведенном ниже примере он работает при нажатии внутри панели «Сетка», но это не означает, что щелчок по ячейке (UIElement внутри ячейки) DataGrid.WPF DataGrid: Показать динамическое контекстное меню по левому щелчку

В чем разница? Что мне нужно сделать, чтобы заставить его работать и с 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);

Но почему установка IsOpen внутри MouseDown случае не работает?

+0

у вас проверены ответы – AnjumSKhan

+0

У меня все еще нет ответа. Я только что нашел обходное решение. Вопрос в том, почему MouseDown для DataGrid не работает, пока он работает, например, на панели Grid. –

+0

То, что я упомянул, является стандартным способом отображения динамического контроля меню msdn – AnjumSKhan

ответ

0

О первом решении.

есть некоторые проблемы при использовании события MouseDown, поскольку событие может быть помечено как обработано другими элементами управления. PreviewMouseDown - это событие предварительного просмотра, и оно не помечено, поэтому, когда вы его используете, оно полностью исчезает от корневого элемента и элементов управления до вашей реализации.

для получения дополнительной информации вы можете прочитать здесь: MSDN UIElement.MouseDown Event

+0

Событие MouseDown не обрабатывается каким-либо другим элементом управления. Установка контрольной точки показывает, что точка останова запускается всякий раз, когда я нажимаю. Но должно быть что-то, что препятствует отображению ContextMenu. –

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;. Также полезно использовать предварительные события, если вы хотите сделать предварительную подготовку.

Смежные вопросы