简体   繁体   中英

WPF: Command on listbox item context menu / menu item does not work even though it does on a button

I have a custom RoutedUICommand that works fine when bound to the Command property of a button. Yet when bound to a ConextMenu MenuItem on a Listbox's item it does not work. The CanExecute method is not called, and thus the item is left disabled in the context menu. The CanExecute is called from the button's binding however.

In the repo example below, CrawlCommands.AddCredit is the command. It is bound to both a button and ListBoxItems. The Button behaves as expected, but the ListBoxItem does not. Right clicking on a list box item does show the context menu, and the menu item's header is dervied from the Command properly, but the CanExecute is never called, so it never knows the command is valid and thus stays disabled.

What am I missing?

<UserControl x:Class="CrawlSpace.TestCommands"
         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" 
         xmlns:local="clr-namespace:CrawlSpace"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" Background="#FF020523">


<UserControl.CommandBindings>
    <CommandBinding Command="local:CrawlCommands.AddCredit" Executed="ExecutedAddCredit" CanExecute="CanExecuteAddCredit"/>
</UserControl.CommandBindings>

<Grid>

    <Grid.Resources>
        <local:MockData x:Key="TestData"/>
    </Grid.Resources>

    <Grid.Background>
        <SolidColorBrush Color="DarkGray"/>
    </Grid.Background>
    <Grid.RowDefinitions>
        <RowDefinition Height="7*"/>
        <RowDefinition Height="3*"/>
    </Grid.RowDefinitions>

    <!-- A button with a command, this one works! -->

    <Button x:Name="button" Command="local:CrawlCommands.AddCredit" Content="Add Credit" Margin="10" Grid.Row="1" Width="177"/>

    <ListBox x:Name="listBox" Margin="10" Background="LightBlue" ItemsSource="{StaticResource TestData}">
        <ListBox.Resources>
            <!-- Define a context menu -->
            <ContextMenu x:Key="ItemMenu">
                <MenuItem Command="local:CrawlCommands.AddCreditBlock"/>
            </ContextMenu>

            <!-- Sets a context menu for each ListBoxItem in the current ListBox -->
            <Style TargetType="{x:Type ListBoxItem}">

                <!-- This menu item will not function even though the button verison above does -->
                <Setter Property="ContextMenu" Value="{StaticResource ItemMenu}"></Setter>
            </Style>
        </ListBox.Resources>

        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding FirstName}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

Refer my code. It is working fine for me.

<UserControl x:Class="DragDrop_Learning.UserControl1"
         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" 
         xmlns:local="clr-namespace:DragDrop_Learning"
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.CommandBindings>
    <CommandBinding Command="local:CrawlCommands.AddCredit" Executed="ExecutedAddCredit" CanExecute="CanExecuteAddCredit"/>
    <CommandBinding Command="local:CrawlCommands.AddCreditBlock" Executed="ExecutedAddCreditBlock" CanExecute="CanExecuteAddCreditBlock"/>
</UserControl.CommandBindings>

<Grid>

    <Grid.Resources>

    </Grid.Resources>

    <Grid.Background>
        <SolidColorBrush Color="DarkGray"/>
    </Grid.Background>
    <Grid.RowDefinitions>
        <RowDefinition Height="7*"/>
        <RowDefinition Height="3*"/>
    </Grid.RowDefinitions>

    <!-- A button with a command, this one works! -->

    <Button x:Name="button" Command="local:CrawlCommands.AddCredit" Content="Add Credit" Margin="10" Grid.Row="1" Width="177"/>

    <ListBox x:Name="listBox" Margin="10" Background="LightBlue" >
        <ListBox.Resources>
            <!-- Define a context menu -->
            <ContextMenu x:Key="ItemMenu">
                <MenuItem Command="local:CrawlCommands.AddCreditBlock"/>
            </ContextMenu>

            <!-- Sets a context menu for each ListBoxItem in the current ListBox -->
            <Style TargetType="{x:Type ListBoxItem}">

                <!-- This menu item will not function even though the button verison above does -->
                <Setter Property="ContextMenu" Value="{StaticResource ItemMenu}"></Setter>
            </Style>
        </ListBox.Resources>

        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding FirstName}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

 public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        List<Person> lst = new List<Person>();
        listBox.ItemsSource = lst;
        lst.Add(new Person() { FirstName="Test"});
    }

    private void CanExecuteAddCredit(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    private void ExecutedAddCredit(object sender, ExecutedRoutedEventArgs e)
    {

    }
    private void CanExecuteAddCreditBlock(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    private void ExecutedAddCreditBlock(object sender, ExecutedRoutedEventArgs e)
    {

    }
}

public static class CrawlCommands
{
    public static readonly RoutedUICommand AddCredit = new RoutedUICommand
            (
                    "AddCredit",
                    "AddCredit",
                    typeof(CrawlCommands)
            );

    public static readonly RoutedUICommand AddCreditBlock = new RoutedUICommand
            (
                    "AddCreditBlock",
                    "AddCreditBlock",
                    typeof(CrawlCommands)
            );
}

class Person
{
    private string myVar;

    public string FirstName
    {
        get { return myVar; }
        set { myVar = value; }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM