-1

I'm trying to learn Commanding and have set up a simple wpf project to use a custom command. I have a ListBox and a Button on a Window. When the ListBox has the focus and an Item is selected, I want the Button to be enabled, otherwise it should be disabled.

I define a CustomCommand in a separate CustomCommands class:

Public Shared ReceivedFocus As New RoutedCommand

and in my Window I set it up as follows:

<CommandBinding
    Command="{x:Static local:CustomCommands.ReceivedFocus}"
    CanExecute="CanActivate"
    Executed="ChangeSelection">
</CommandBinding>

and use the command for the ListBox as follows:

<ListBox
    x:Name="lstInactive">
    <i:Interaction.Triggers>
        <i:EventTrigger
            EventName="GotFocus">
            <i:InvokeCommandAction
                Command="{x:Static local:CustomCommands.ReceivedFocus}"
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>

and, finally, the CanActivate routine is:

Private Sub CanActivate(sender As Object, e As CanExecuteRoutedEventArgs)
        If lstInactive.SelectedIndex >= 0 Then
            e.CanExecute = True
        Else
            e.CanExecute = False
        End If
End Sub

This is not working. The major problem is that I don't understand how to relate the CanExecute value to the Button. Should I ignore the CanExecute value in the CanActivate routine and instead just set the Enabled property of the Button? If so, what is the value of the CanExecute paramter of the CanExecuteRoutedEventArgs?

A second problem is that the GotFocus event is not firing until I select an item in the ListBox a second time.

Or maybe I don't have a grasp on Commanding at all and this is not the right approach. This small project is not important in itself, it is intended to make sure I understand Commanding after reading numerous articles about it before I start to use Commands in "real" projects. Sadly, at this stage it is clear I don't.

SezMe
  • 527
  • 8
  • 24
  • If you want a `Button` to represent the command's state, you indeed need to bind the `Button.Command` property to that command. I'd recommend you to create commands in a view-model rather than using static references and `CommandBinding`. Doing so, you'll have a well defined concept that separates the logic from the representation. Bind the `ListBox.SelectedItem` to a view-model's property and decide in the view-model whether the command can execute or not. – dymanoid Nov 28 '17 at 14:43
  • What is the basis for the down vote? – SezMe Nov 29 '17 at 22:18

1 Answers1

0

This is not working. The major problem is that I don't understand how to relate the CanExecute value to the Button.

Bind its Command property to the same command:

<Button Content="Button" Command="{x:Static local:CustomCommands.ReceivedFocus}" />

The Button should then be enabled or disabled based on the value that you set the CanExecute property to in your CanActivate event handler.

You probably also want to listen to the SelectionChanged event. This works as expected:

<StackPanel>
    <StackPanel.CommandBindings>
        <CommandBinding
                Command="{x:Static local:CustomCommands.ReceivedFocus}"
                CanExecute="CanActivate"
                Executed="ChangeSelection">
        </CommandBinding>
    </StackPanel.CommandBindings>

    <ListBox x:Name="lstInactive">
        <ListBoxItem>first</ListBoxItem>
        <ListBoxItem>second</ListBoxItem>
        <ListBoxItem>third</ListBoxItem>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <i:InvokeCommandAction Command="{x:Static local:CustomCommands.ReceivedFocus}">
                </i:InvokeCommandAction>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </ListBox>

    <Button Content="Button" Command="{x:Static local:CustomCommands.ReceivedFocus}" />
</StackPanel>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void CanActivate(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = lstInactive.SelectedIndex >= 0;
    }

    private void ChangeSelection(object sender, ExecutedRoutedEventArgs e)
    {

    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • @mm That does not work because it forces the Button to execute the same command as selecting an item in the list boxes. In my app the ONLY action to be taken is to set e.CanExecute of several buttons on the Window. – SezMe Dec 01 '17 at 16:20
  • I did get help from your answer and have modified my code accordingly. I set the command of the button to a different routine and set up the ListBox GotFocus and Selection change commands to set e.CanExecute=True. However, for some reason this is still not changing the IsEnabled button property to True. I can post the modified code if that would help. – SezMe Dec 01 '17 at 16:24
  • BTW I was aware of the need to "watch" the SelectionChanged event of the ListBox. I just wanted to let you know I am not completely incompetent; it just appears that way. – SezMe Dec 01 '17 at 16:25
  • The IsEnabled property isn't supposed to change. You don't use it when you bind to a Command, i.e. you *either* enable the button using the IsEnabled property *or* using the CanExecute method of a command. – mm8 Dec 04 '17 at 09:59