0

I am relatively new to WPF, so this may be trivial, but I couldn't figure this out. Let's say I have a ListBox and a Button. The button is binded to a command that does something on the selected item of the list.

Example:

<ListBox Name="List" ItemsSource="{Binding Items}" />
<Button Content="Show!" Command="{Binding ShowCommand}" CommandParameter="{Binding ElementName=List, Path=SelectedItem}"/>

I want the button to be disabled if and only if no item is selected, and I ideally want to do it via the ShowCommand.CanExecute function. I tried checking for null parameter and it worked but if only checked once in the beginning. If I select an item the button is still disable.

I tried the suggestion here: WPF CommandParameter binding not updating but it simply didn't work... (same problem) Am I doing something wrong?

How do I make him recall canExecute when I select an item on the list? .

Shachar Har-Shuv
  • 666
  • 6
  • 24
  • Possible duplicate of [WPF CommandParameter binding not updating](https://stackoverflow.com/questions/3092339/wpf-commandparameter-binding-not-updating) – ASh Feb 20 '18 at 14:53
  • What implementation of the ICommand are you using? – mm8 Feb 20 '18 at 15:24

2 Answers2

1

You can achieve that easily using a DataTrigger

<ListBox Name="List" ItemsSource="{Binding Items}" />
<Button Content="Show!" Command="{Binding ShowCommand}" CommandParameter="{Binding ElementName=List, Path=SelectedItem}">
        <Button.Style>
            <Style TargetType="Button">
                <Setter Property="IsEnabled" Value="True" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SelectedItem,ElementName=List}" Value="{x:Null}">
                        <Setter Property="IsEnabled" Value="False"></Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
</Button>

Update

The reason why ou couldn't achieve that using CanExecute is most likely because the CanExecuteChanged event wasn't raised, to fix that you can take advantage of CommandManager.RequerySuggested by linking this event to your command's CanExecuteChanged event[1].

Here a basic implementation and use of an ICommand in your case:

public class Command : ICommand
{
    private readonly Action<object> _action;
    public Command(Action<object> action)
    {
        _action = action;
    }
    public bool CanExecute(object parameter)
    {
        //the selected item of the ListBox is passed as parameter
        return parameter != null;
    }
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        //the selected item of the ListBox is passed as parameter
        _action(parameter);
    }
}

The command defined in your VM should look something like that:

 private ICommand _showCommand;
    public ICommand ShowCommand => _showCommand ?? (_showCommand = new Command(ButtonClickAction));

    public void ButtonClickAction(object parameter)
    {
       //Your action
    }

You might also want to take a look at Routed Commands to avoid raising the CanExecuteChanged event yourself.

SamTh3D3v
  • 9,854
  • 3
  • 31
  • 47
  • That is a simple solution indeed but it will require me to redo this on a several buttons if they are bound to the same command. Also, imagine to command will be binded to some item in a menu, I would like this functionality to work as well. – Shachar Har-Shuv Feb 20 '18 at 14:55
  • Nah, just define a global style and apply it to those buttons! – SamTh3D3v Feb 20 '18 at 14:57
  • 1
    I already have styles to the buttons. It would be a pain to apply a different style to every button with the same command. I like better the solution with the "CanExecute" function. it's neat and comfortable. Only it's not working for me here for some reason... – Shachar Har-Shuv Feb 20 '18 at 15:04
  • The new answer sounds good! But suppose I want the parameter in the execute function. I would I accomplish that? – Shachar Har-Shuv Feb 20 '18 at 17:52
  • The parameter is by default passed to both the Execute and CanExecute methods as an object! – SamTh3D3v Feb 20 '18 at 17:54
  • but in your new solution you called an action passed by the ViewModel! This action has no parameter at all. – Shachar Har-Shuv Feb 20 '18 at 17:58
  • In that case change the `private readonly Action _action` to `private readonly Action _action` , and pass the parameter to it – SamTh3D3v Feb 20 '18 at 18:02
0

You can achieve it in few solutions: 1) Binding the SelecteItem of the ListBox to some property in the view model, and on the property setter call to ShowCommand.RaiseCanExecuteChanged(). 2) Binding the IsEnabled of the button to the SelecteItem of the ListBox with some converter which convert null to boolean.

Omri Aviv
  • 126
  • 1
  • 3