0
votes

I need to use a context menu to restart services based on a datagrid (the context menu should send the name of the service as a CommandParameter)

The ContextMenu shows properly but clicking the MenuItems does not trigger the command (breakpoint not reached) but setting the context menu directly to a checkbox for example triggers the commands perfectly.

Ultimately, what I want is to get the context menu on right click on any item of the datagrid, clicking the menuitem should send either the Name column value or the whole selected item to the command in ViewModel (and then restart the process from there).

Really hurting my head for a few days, if you have any hints...

My Datagrid :

<DataGrid x:Name="dgServices" HorizontalAlignment="Left" VerticalAlignment="Top" DockPanel.Dock="Top" Height="auto" HeadersVisibility="Row"
              AutoGenerateColumns="False" HorizontalGridLinesBrush="#FFC7E0EE" VerticalGridLinesBrush="#FFC7E0EE" SelectionMode="Single" BorderThickness="0"
              ItemContainerStyle="{StaticResource DefaultRowStyle}" ItemsSource="{Binding Source={StaticResource cvsServ}}">
            <DataGrid.GroupStyle>
                //GROUPSTYLE
            </DataGrid.GroupStyle>
            <DataGrid.Columns>
                <DataGridTemplateColumn Width="30"/>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="373">
                </DataGridTextColumn>
                <DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="356"/>
            </DataGrid.Columns>
        </DataGrid>

ContainerStyle and ContextMenu in Window.Resources :

<Window.Resources>
<ContextMenu  x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
    <MenuItem Header="NULL" Command="{Binding restartService}"/>
    <MenuItem Header="NAME" CommandParameter="{Binding PlacementTarget.Name, RelativeSource={RelativeSource FindAncestor,AncestorType=ContextMenu}}" Command="{Binding restartService}"/>
    <MenuItem Header="ITEM" CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource FindAncestor,AncestorType=ContextMenu}}" Command="{Binding restartService}"/>
    <MenuItem Header="ITEMS" CommandParameter="{Binding PlacementTarget.SelectedItems, RelativeSource={RelativeSource FindAncestor,AncestorType=ContextMenu}}" Command="{Binding restartService}"/>
</ContextMenu>

 <Style x:Key="DefaultRowStyle" TargetType="{x:Type DataGridRow}">
    <Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
 </Style>

<CollectionViewSource x:Key="cvsServ" Source="{Binding services, UpdateSourceTrigger=PropertyChanged}">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="Key" />
    </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

The Checkbox used for testing :

<CheckBox IsChecked="{Binding autoStart, Mode=TwoWay}">
                <Label Content="AutoStart"/>
                <CheckBox.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Edit" CommandParameter="{Binding PlacementTarget, RelativeSource={RelativeSource FindAncestor,AncestorType=ContextMenu}}" Command="{Binding restartService}"/>
                        <!--<MenuItem Header="Edit" CommandParameter="{Binding ElementName=dgServices, Path=SelectedItem}" Command="{Binding restartService}"/>-->
                    </ContextMenu>
                </CheckBox.ContextMenu>
            </CheckBox>

ViewModel :

    private DelegateCommand _restartService;
    public DelegateCommand restartService
    {
        get
        {
            return _restartService ?? (_restartService = new DelegateCommand(o => TestCommand(o), o => true));
            //return _restartService ?? (_restartService = new DelegateCommand(o => MessageBox.Show($"{o.ToString()}\n{o.GetType()}"), o => true));
            //return _restartService ?? (_restartService = new DelegateCommand(o => Process.Start(new ProcessStartInfo("C:\\Windows\\system32\\cmd.exe", "/c net start "+o.ToString()) { Verb = "runas" }), o => true));
        }

    private void TestCommand(object o)
    {
        MessageBox.Show(o?.GetType()?.ToString() ?? "NULL");
    }
1
Is your command defined in the same ViewModel with services collection? Or in view model representing the separate item in services collection?Pavel Anikhouski
Try this: <MenuItem Header="NAME" Command="{Binding PlacementTarget.DataContext.restartService, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}"/>mm8
@mm8 this did not trigger the command either, and is it purposely missing the commandparameter?Phoque
@PavelAnikhouski Yes the Command is defined in the same view model as the collection servicesPhoque
@Phoque: What is PlacementTarget.Type ? Where is the Type property defined?mm8

1 Answers

1
votes

If the command property is defined in the view model of the DataGrid, you could bind the Tag property of the row to the DataGrid:

<Style x:Key="DefaultRowStyle" TargetType="{x:Type DataGridRow}">
    <Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
    <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}" />
</Style>

...and then try this:

<MenuItem Header="NAME"
          Command="{Binding PlacementTarget.Tag.DataContext.restartService, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}"
          CommandParameter="{Binding PlacementTarget.Tag.Name, RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}"/>