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!
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>
Just as reference... I had the same problem using a UserControl. I had too many MenuItems and I also wanted to make sure to not forget that line on new MenuItem. Then I went for a Style as this:
<UserControl.Resources>
<Style TargetType="MenuItem">
<Setter Property="CommandTarget" Value="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"></Setter>
</Style>
...
Please, if you ever want to give me a thumbs up... give it to Vinkal who really identify the problem and found the solution. This guy is a genious!!!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With