1
votes

I'm using Josh Smith RelayCommand class in a WPF MVVM app for creating my commands inside my ViewModel:

For example:

ICommand RemoveAllCommand = new RelayCommand<object>(OnRemoveAll, CanRemoveAll);

I am calling this command from a ContextMenu:

<ContextMenu x:Key="MyContextMenu" DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
    <MenuItem Header="Remove All" Command="{Binding Path=DataContext.RemoveAllCommand,
                                  RelativeSource={RelativeSource AncestorType={x:Type TreeView}}}" CommandParameter="{Binding Path=.Header}" />

Everything works fine, except that my MenuItem's is still visible but disabled, I would like to set the Visibility to Collapsed so that my MenuItem doesn't show up when CanExecute in Relay Command returns false.

I tried to set a binding to Visibility property, but I don't know how to bind to my CanRemoveAll(object obj) method with parameter. I also thought about using a DataTrigger but I'm not sure how to do it.

Here is my CanRemoveAll method in the ViewModel:

    public bool CanRemoveAll(object param)
    {
        GoldTreeNodeViewModel gtn = param as GoldTreeNodeViewModel;
        return (gtn != null && gtn.Children != null && gtn.Children.Count > 0);
    }

From the RelayCommand class:

public event EventHandler CanExecuteChanged
    {
        add
        {
            if (_canExecute != null)
                CommandManager.RequerySuggested += value;
        }
        remove
        {
            if (_canExecute != null)
                CommandManager.RequerySuggested -= value;
        }
    }

    [DebuggerStepThrough]
    public Boolean CanExecute(Object parameter)
    {
        return _canExecute == null ? true : _canExecute((T) parameter);
    }

Any help will be highly appreciated,

1
Can you please show the code of CanRemoveAll in VM and also from where you Raising CanExecuteChanged. - yo chauhan
Just added that info to the question.. Also I'm not Raising the CanExecuteChanged explicitly anywhere, I think the RelayCommand and WPF internals take care of that as far as I know. - Adolfo Perez

1 Answers

1
votes
 <ContextMenu x:Key="MyContextMenu" DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
        <MenuItem Header="Remove All" Command="{Binding Path=DataContext.RemoveAllCommand,
                              RelativeSource={RelativeSource AncestorType={x:Type TreeView}}}" CommandParameter="{Binding Path=.Header}" 
                  Visibility="{Binding DataContext.RemoveVisibility,RelativeSource={RelativeSource AncestorType={x:Type TreeView}}}"
                  />

private Visibility _removeVisibility;

    public Visibility RemoveVisibility
    {
        get { return _removeVisibility; }
        set { _removeVisibility = value; Notify("RemoveVisibility"); }
    }

    public bool CanRemoveAll(object param)
    {
        GoldTreeNodeViewModel gtn = param as GoldTreeNodeViewModel;
        bool result= (gtn != null && gtn.Children != null && gtn.Children.Count > 0);
        if (result)
            RemoveVisibility = Visibility.Visible;
        else
            RemoveVisibility = Visibility.Collapsed;
        return result;
    }

I think that DataContext you have binded correspond to your ViewModel . I hope this will help.