0

My command is inside my ViewModel. I need to pass the DataGrid where my Menuitem is nested. How is this possible ?

<MenuItem Header="Delete item/s" Command="{Binding RemoveHistoryItem}" CommandParameter="{Binding ElementName=HistoryDataGrid}">
3
  • 1
    The DataGrid is a UI Element, you can't interact with UI element in your ViewModel. You want to send a HistoryItem in the CommandParameter. Commented Mar 10, 2013 at 19:28
  • Maybe... The SelectedItem Collection. For a different MenuItem the total count of items. But its still the same problem. Commented Mar 10, 2013 at 19:38
  • 1
    Maybe this might work. ... CommandParameter="{Binding ElementName=HistoryDataGrid, Path=DataContext}" ... Commented Mar 10, 2013 at 20:51

1 Answer 1

1

You should definitely not send the UIElement back to your ViewModel (like Jeffery stated). Try to bind the DataGrid properties you need to the ViewModel, then access them inside the command handler.

I used a button for illustration, but this will work for your MenuItem in the same way.

ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public ICommand RemoveHistoryItemCommand { get; private set; }

    private HistoryItem _selectedHistoryItem;
    public HistoryItem SelectedHistoryItem { get { return _selectedHistoryItem; } set { _selectedHistoryItem = value; OnPropertyChanged("SelectedHistoryItem"); } }

    private ObservableCollection<HistoryItem> _historyItems = new ObservableCollection<HistoryItem>();
    public ObservableCollection<HistoryItem> HistoryItems { get { return _historyItems; } set { _historyItems = value; OnPropertyChanged("HistoryItems"); } }


    public ViewModel()
    {
        this.RemoveHistoryItemCommand = new ActionCommand(RemoveHistoryItem);

        this.HistoryItems.Add(new HistoryItem() { Year = "1618", Description = "Start of war" });
        this.HistoryItems.Add(new HistoryItem() { Year = "1648", Description = "End of war" });
    }

    // command handler
    private void RemoveHistoryItem()
    {            
        if (this.HistoryItems != null)
        {
            HistoryItems.Remove(this.SelectedHistoryItem);
        }
    }
}

public class HistoryItem
{
    public string Year { get; set; }
    public string Description { get; set; }
}

public class ActionCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
    public Action _action;
    public ActionCommand(Action action)
    {
        _action = action;
    }

    public bool CanExecute(object parameter) { return true; }

    public void Execute(object parameter)
    {
        if (CanExecute(parameter))
            _action();
    }
}

Xaml:

<Window.DataContext>
    <local:ViewModel />
</Window.DataContext>


<StackPanel>
    <DataGrid ItemsSource="{Binding HistoryItems}" SelectedItem="{Binding SelectedHistoryItem, Mode=TwoWay}" />
    <Button Content="Remove selected item" Command="{Binding RemoveHistoryItemCommand}" HorizontalAlignment="Left" />
</StackPanel>
Sign up to request clarification or add additional context in comments.

1 Comment

just to complete the answer - @abc this is the right approach - i.e. use the same view model to back both controls (or are part of the same 'large' view model), then communicate things behind the scenes. If you do need to send some gui element - use what [Binding ElementName= Path=DataContext.Property...] as @failedprogramming mentioned.

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.