2017-05-12 5 views
0

UPDATE !!! Ich habe entdeckt, dass auch dies nicht funktioniert, wenn ich es im Datagrid setzen:ContextMenu auf DataGrid in WPF/MVVM abrufen

<DataGrid.ContextMenu> 
      <ContextMenu > 
       <MenuItem Header="Add Divider" Click="MenuItem_Click" /> 
      </ContextMenu> 
     </DataGrid.ContextMenu> 

Dies funktioniert auf jeden Fall in einem Dummy-Projekt von Grund auf neu aufgebaut. Ich glaube also nicht, dass ich verbindliche Probleme oder Datenprobleme habe ... Ich komme nicht so weit. Ich vermute, dass ein anderer Teil des Programms das Kontextmenü abfängt und bearbeitet (oder mit der rechten Maustaste klickt). Ich habe den ursprünglichen Code nicht geschrieben und es ist eine große Codebasis. Kann mir jemand eine Idee geben, wonach ich suchen soll? Was würde verhindern, dass das ContextMenu auf dem DataGrid aufgerufen wird. Beachten Sie, dass sich das DataGrid in einem ScrollViewer und StackPanel befindet und das gesamte Steuerelement Teil eines größeren Fensters ist. Tatsächlich ist es eine von vielen Registerkarten.
-END UPDATE

Ich ziehe mir die Haare aus dem Versuch, ein Kontextmenü auf meinem DataGrid in meinem WPF/MVVM-Projekt zu bekommen. Ich poste das XAML und ViewModel unten. Ich würde gerne in der Lage sein, mit der rechten Maustaste auf eine Zeile zu klicken und einen Befehl im ViewModel aufzurufen, der einen der Spalteneinträge für diese Zeile ändern würde.

Die XAML (rufe ich, was ich denke, sind die wichtigsten Punkte unten)

<UserControl x:Class="Sears.UserInterface.Views.Technician.Alerts.AlertsLogView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="clr-namespace:Sears.UserInterface.Views.Technician.Alerts" 
     xmlns:converters="clr-namespace:Common.Controls.Converters;assembly=Common.Controls" 
     mc:Ignorable="d" 
     d:DesignHeight="800" 
     d:DesignWidth="1200"> 
<UserControl.Resources> 
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> 
    <converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" /> 

</UserControl.Resources> 

<StackPanel Orientation="Horizontal"> 
    <ScrollViewer> 
     <DataGrid Width="1000" 
        Margin="0" 
        HorizontalAlignment="Left" 
        AutoGenerateColumns="False" 
        Background="Transparent" 
        DataContext="{Binding}" 
        HeadersVisibility="Column" 
        ItemsSource="{Binding Alerts}" 
        SelectedItem="{Binding SelectedItemProperty, Mode=TwoWay}" 
        RowBackground="Transparent" 
        RowHeight="30" 
        Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}" 
      > 


      **<DataGrid.ContextMenu> 
       <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"> 

        <MenuItem Command="{Binding CloseAlertCommand}" Header="Close Alert"/> 
       </ContextMenu> 
      </DataGrid.ContextMenu>** 


      <DataGrid.CellStyle> 
       <Style TargetType="{x:Type DataGridCell}"> 
        <Setter Property="Foreground" Value="Black" /> 
        <Style.Triggers> 
         <Trigger Property="IsSelected" Value="True"> 
          <Setter Property="Background" Value="{x:Null}" /> 
          <Setter Property="BorderBrush" Value="{x:Null}" /> 
         </Trigger> 
        </Style.Triggers> 
       </Style> 
      </DataGrid.CellStyle> 
      <DataGrid.ColumnHeaderStyle> 
       <Style TargetType="{x:Type DataGridColumnHeader}"> 
        <Setter Property="FontWeight" Value="Bold" /> 
       </Style> 
      </DataGrid.ColumnHeaderStyle> 
      <DataGrid.Columns> 
       <DataGridTemplateColumn Width="*" Header="Id"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Id}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Width="*" Header="TimeStamp"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding AlertTime}" > 

          </TextBlock> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Width="*" Header="Severity"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Severity}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Width="*" Header="AlertText"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding AlertText}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Width="*" Header="Details"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Details}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Width="*" Header="Active"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Active}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Width="*" Header="Acknowledged"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Acknowledged}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 

       <DataGridTemplateColumn Width="*" Header="Reported"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Reported}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 

       <DataGridTemplateColumn Width="*" Header="Status"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Status}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 

       <DataGridTemplateColumn Width="*" Header="Resolution"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Resolution}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 

       <DataGridTemplateColumn Width="*" Header="Category"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock VerticalAlignment="Center" 
             Padding="5" 
             Text="{Binding Category}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 

      </DataGrid.Columns> 
     </DataGrid> 
    </ScrollViewer> 
</StackPanel> 

Hinweis der DataGrid.ContextMenu Teil. Ich habe StackOverflow durchsucht und verschiedene Ideen ausprobiert, um das Kontextmenü aufzurufen. Nichts. Dieses spezielle Beispiel verwendet "Tag". Ich versuchte auch, das contextmenu in den Betriebsmittelabschnitten wie zu setzen:

<ContextMenu x:Key="DataRowContextMenu" DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}}"> 
     <MenuItem x:Name="RowContMenuTransfer" Header="Close Alert" Command="{Binding DataContext.CloseAlertCommand}" CommandParameter="{Binding}" > 
     </MenuItem> 
    </ContextMenu> 

Der "Umbau" Weise, es zu tun resultiert in keinen verbindlichen Fehlern. Du hast nur einen Rechtsklick und nichts! Andere Wege (die ich posten kann) gaben verbindliche Fehler im Ausgabefenster. Beachten Sie, dass sich das DataGrid in einem ScrollViewer und StackPanel befindet. Hier

ist das Ansichtsmodell

public class AlertsLogViewModel : ViewModelBase, IAlertsLogViewModel, IDisposable 
{ 
    private IAlertManager _model; 
    private readonly object _lock = new object(); 
    private ICommand _closeAlertCommand; 

    public AlertsLogViewModel(IAlertManager model) : base("AlertsLogViewModel") 
    { 
     Alerts = new ObservableCollection<IAlert>(); 
     _model = model ?? throw new ArgumentNullException("model"); 
     _model.AlertStatusUpdated += _model_AlertStatusUpdated; 
     UpdateAlerts(); 
    } 

    public IAlert SelectedItemProperty { get; set; } 
    public ICommand CloseAlertCommand 
    { 
     get { return _closeAlertCommand ?? (_closeAlertCommand = new DelegateCommand(CloseAlert)); } 
    } 

    private void CloseAlert() 
    { 
     _model.CloseAlert(SelectedItemProperty.SystemErrorGuid); 
    } 

    public ObservableCollection<IAlert> Alerts { get; private set; } 
    private void _model_AlertStatusUpdated(object sender, DataAccess.AlertStatusEventArgs e) 
    { 
     UpdateAlerts(); 
    } 

    private void UpdateAlerts() 
    { 

     RunOnDispatcher(() => 
      { 
       lock (_lock) 
       { 
        var modelAlerts = _model.GetAlerts().OrderBy(p => (int)p.Status).ThenByDescending(p => p.AlertTime); 
        Alerts.Clear(); 
        if (modelAlerts != null) 
        { 
         foreach (var alert in modelAlerts) 
         { 
          Alerts.Add(alert); 
         } 
        } 

       } 
      } 
     ); 
     NotifyPropertyChanged("Alerts"); 

    } 
    public void Dispose() 
    { 
     if (_model != null) 
      _model.AlertStatusUpdated -= _model_AlertStatusUpdated; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

Notiere die CloseAlertCommand und SelectedItemProperty. Ich sehe, dass SelectedItemProperty aufgerufen wird, wenn ich Linksklick, aber nicht mit der rechten Maustaste. CloseAlert wird nie aufgerufen.

Schließlich, falls relevant es ist, möchte ich erwähnen, dass die AlertsLogView in einer Technicial.xaml Seite ist, und es ist hier, dass es an die Viewmodel gebunden ist:

<TabItem Header="Alerts" 
       PreviewMouseDown="OnPreviewMouseDown" 
       PreviewTouchDown="OnPreviewTouchDown"> 
      <alertlog:AlertsLogView Margin="5" 
               DataContext="{Binding AlertsLogViewModel}" /> 
     </TabItem> 

für Hinweise, Referenzen Vielen Dank, Zeiger oder Lösungen!

-Dave

+1

In vereinfachter Form funktioniert Ihr Code für mich .. Versuchen Sie, nicht den Befehl aber Header zu einer Eigenschaft in VM zu binden und sehen, ob es Wert bekommt. Kann es sein, dass du irgendwie eine tote Sperre hast? Sie verwenden lock() .. – Rekshino

+0

Intriguing. Können Sie den vereinfachten Code angeben (oder teilen)? Was musstest du rausnehmen? Danke für das Lesen meiner Frage! – Dave

+0

Rekshino, habe ich Command Binding entfernt und eine Bindung von Header (MenuItem in ContextMenu zu ViewModel Eigenschaft. Kein Glück. – Dave

Antwort

1

So, wie ich bereits in den Kommentaren geschrieben haben, die Bindung funktioniert. Ich habe gedacht, dass Sie ContextMenu aufgerufen haben, aber Sie schreiben Sie nicht.MouseRightButtonClick kann durch verschiedene Dinge abgefangen werden:

  • implizite oder explizite Stile für Gitter oder es Eltern (Wenn explicit - es Kommentar aus, wenn implizit - stellen Sie Ihren eigenen Dummy-Stil)
  • Behaviors für Gitter oder Eltern (Kommentar it out)
  • hinter-Code (überprüfen, ob es Event-Handler in Gitter oder Eltern) konsequent

Machen Sie es und Sie werden feststellen, was für das Problem verantwortlich ist.

+0

Danke Rekshino. Das war es In ParentWindow (einige Ebenen höher) war private void OnPreviewMouseRightButtonDown (Objekt Absender, MouseButtonEventArgs e) ODER in XAML PreviewMouseRightButtonDown = "OnPreview MausRightButtonDown " – Dave