WPF listbox with contextmenu canexecute not called until something selected

commandbinding, contextmenu, listbox, wpf

Solution

This is a known bug as mentioned here. If there is no focused element in the window's main focus scope, the `CanExecute` routing will stop at the `ContextMenu`, so it will not reach to the `CommandBinding` on the Window, one workaround is to bind `MenuItem`'s `CommandTarget` to the main window, as following code demonstrates:

<ListBox.ContextMenu>
    <ContextMenu>
        <MenuItem Command="SelectAll"
                    CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}">
        </MenuItem>
    </ContextMenu>
</ListBox.ContextMenu>

Below is the complete code:

<UserControl x:Class="ListBoxStyle.ListBoxUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.CommandBindings>
        <CommandBinding Command="SelectAll" CanExecute="SelectAll_CanExecute" Executed="SelectAll_Executed"/>
    </UserControl.CommandBindings>
    <Grid>
        <ListBox x:Name="listbox" 
             Background="Transparent" 
             SelectionMode="Extended"
             ScrollViewer.VerticalScrollBarVisibility="Auto">
            <ListBox.ContextMenu>
                <ContextMenu>
                    <MenuItem Command="SelectAll"
                    CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}">
                    </MenuItem>
                </ContextMenu>
            </ListBox.ContextMenu>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Background="Transparent">
                        <CheckBox Name="cbEnabled" IsChecked="{Binding Enabled, Mode=TwoWay}" Margin="0,2,0,0"/>
                        <TextBlock Text="{Binding}" Padding="5,0,0,0"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

Problem

I have a ListBox the ItemTemplate bound to an ObservableCollection of my items. At the moment, I'm trying to implement Cut/Copy/Paste/SelectAll (To keep it short, I'll just show selectall here...) ``` <UserControl.CommandBindings> <CommandBinding Command="SelectAll" CanExecute="SelectAll_CanExecute" Executed="SelectAll_Executed"/> </UserControl.CommandBindings> <ListBox x:Name="listbox" ItemsSource="{Binding}" Background="Transparent" SelectionMode="Extended" ScrollViewer.VerticalScrollBarVisibility="Auto"> <ListBox.ContextMenu> <ContextMenu> <MenuItem Command="SelectAll" /> </ContextMenu> </ListBox.ContextMenu> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Background="Transparent"> <CheckBox Name="cbEnabled" IsChecked="{Binding Enabled, Mode=TwoWay}" Margin="0,2,0,0"/> <TextBlock Text="{Binding Name}" Padding="5,0,0,0"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> ``` this is the codebehind for canexecute: ``` private void SelectAll_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = listbox.Items.Count > 0; e.Handled = true; } ``` when I first run the program and right-click in the listbox, the "Select All" context menu is always disabled (and SelectAll_CanExecute is never called) until I select something. Is there any way to get this to work like it seems it should? (and without either auto-selecting the first item or making the user have to do it) Thanks!

Original source