1

I have a datagrid being binded to an ObservableCollection. The data grid has a context menu. When context menu item is clicked, the binded command gets triggered, but I would like to pass command parameter that is binded to the Id of the data grid row that is selected. The command gets triggered but the parameter is null.

Below is the code that I have tried.

 <DataGrid Name="users" ItemsSource="{Binding UsersModel}" CanUserAddRows="False" IsReadOnly="True" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Id}" Header="User Id" Width="auto"/>
        <DataGridTextColumn Binding="{Binding Name}" Width="*" Header="User Name"/>
        <DataGridTextColumn Binding="{Binding IsRegistered, Converter={StaticResource BoolToYesNoConverter}}" Width="auto" Header="Registered" />
        <DataGridTextColumn Binding="{Binding RegisteredOn}" Width="*" Header="Registration Date"/>
        </DataGrid.Columns>
        <DataGrid.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Modify" Command="{Binding Modify}" CommandParameter="{Binding Id}"/>
                <MenuItem Header="Delete" Command="{Binding Delete}" CommandParameter="{Binding Id}" />
            </ContextMenu>
        </DataGrid.ContextMenu>
</DataGrid>

I am expecting the Id of the selected row be passed as the command parameter.

7
  • try setting command parameter to "yay" and you will see it is beeing carried on Commented Jun 3, 2019 at 8:58
  • the porblem is related to the fact that the context menue has its on datacontext as far as i am aware Commented Jun 3, 2019 at 8:59
  • "Modify" is my ICommand property. My window datacontext is set to UsersViewModel, items source is binded to UsersModel which is an ObservableCollection<UsersModel> type. Commented Jun 3, 2019 at 9:34
  • And in which class is the "Modify" property defined? Commented Jun 3, 2019 at 9:51
  • 1
    @mm8 "The command gets triggered", so the command properties are obviously defined at the main view model level, where the UsersModel property resides. {Binding Id} will obviously not wok there. Commented Jun 3, 2019 at 10:03

3 Answers 3

1

I would create a SelectedRow property on your viewmodel to store the selected row in the grid, then bind the context menu item command to a command on the viewmodel that references the SelectedRow property. I had to use the PlacementTarget on the context menu relative source.

// in viewmodel

public DelegateCommand ModifyCommand { get; }

ModifyCommand = new DelegateCommand(() => { var Id = SelectedRow.Id; //... });

private UsersModel _selectedRow;
public UsersModel SelectedRow
{
    get => _selectedRow;
    set
    {
        _selectedRow = value;
        OnPropertyChanged(nameof(SelectedRow));
    }
}

// in view

DataGrid Name="users" ItemsSource="{Binding Items}" CanUserAddRows="False" IsReadOnly="True" AutoGenerateColumns="False"
    SelectedItem="{Binding SelectedRow, Mode=TwoWay}" >

// and on context menu
<MenuItem Header="Modify" Command="{Binding PlacementTarget.DataContext.ModifyCommand, 
    RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" />
Sign up to request clarification or add additional context in comments.

1 Comment

As a note, setting Mode=TwoWay on the SelectedItem Binding is redundant. It already binds two-way by default.
0

Add a SelectedId property to your view model (where the UsersModel and the command properties are defined) and bind the DataGrid's SelectedValue property to that property.

Then use SelectedId for the CommandParameter Binding. Of course make sure that SelectedId fires the PropertyChanged event.

<DataGrid ... SelectedValuePath="Id" SelectedValue="{Binding SelectedId}">
    ...
    <DataGrid.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Modify"
                      Command="{Binding Modify}"
                      CommandParameter="{Binding SelectedId}"/>
            <MenuItem Header="Delete"
                      Command="{Binding Delete}"
                      CommandParameter="{Binding SelectedId}" />
        </ContextMenu>
    </DataGrid.ContextMenu>
</DataGrid>

Comments

-1

I asuume that your ViewModel class implemented INotifyPropertyChanged interface and I assume that you implement a method for trigger property changes, here I called this method RaisePropertyChanged. After all of that, define a private field selectedUsers and a property with name of SelectedUsers in your viewModel Class:

private UsersModel selectedUsers;

public UsersModel SelectedUsers
    {
        get => _selectedFields;

        set
        {
            _selectedFields = value;
            Modify.RaiseCanExecuteChanged();
            Delete.RaiseCanExecuteChanged();
        }
    }

After that you add it, you must add SelectionChanged event to your Grid, and then in code-behind set-up value for your seletedUser as below:

private void usersGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        usersViewModel.SelectedUsers = usersGrid.SelectedItem as UsersModel;
    }

And bind selectedItem of DataGrid to selectedUser:

<DataGrid Name="users" ItemsSource="{Binding Items}" CanUserAddRows="False" 
IsReadOnly="True" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedUser}" >

When you do these work, selectedUser is accessable in your viewModel.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.