简体   繁体   中英

Can't bind a ContextMenu action to a Command

I've searched and read anything I can about ContextMenus and binding, and how it's not in the tree... etc. So searching feels like I've exhausted it and just don't understand it.

I'm trying to get my ContextMenu AddTournamentCommand to work, but I simply can't get it to command. I recently found out the easy way through Data Sources to bind to objects, so if there's an easy way other than coding it by hand to wire it up, please let me know. This is what I have so far:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Models="clr-namespace:FumbblApiClient.Models" mc:Ignorable="d" x:Name="FumbblMainWindow" x:Class="FumbblApiClient.MainWindow"
        Title="MainWindow" Height="499.45" Width="639" Loaded="Window_Loaded">
    <Window.Resources>
        <CollectionViewSource x:Key="groupViewSource" d:DesignSource="{d:DesignInstance {x:Type Models:Group}, CreateList=True}"/>
        <CollectionViewSource x:Key="groupTournamentsViewSource" Source="{Binding Tournaments, Source={StaticResource groupViewSource}}"/>
    </Window.Resources>
    <Grid Margin="0,0,2,0">
        <TabControl Margin="10">
            <TabItem Header="Groups">
                <Grid Background="#FFE5E5E5" DataContext="{StaticResource groupViewSource}">
                    <TextBox x:Name="GroupIdTextBox" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="Group ID" VerticalAlignment="Top" Width="100" Grid.Column="1"/>
                    <Button Content="Fetch" HorizontalAlignment="Left" Margin="115,11,0,0" VerticalAlignment="Top" Width="61" Click="GroupFetch_Click" Grid.Column="1" Height="22"/>
                    <ListBox x:Name="groupListView" ItemsSource="{Binding}" Margin="10,38,0,10" SelectionMode="Single" HorizontalAlignment="Left" Width="166" SelectionChanged="GroupList_SelectionChanged">
                    </ListBox>
                    <Grid x:Name="grid1" Margin="181,38,10,0" VerticalAlignment="Top" Height="369">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <Label Content="Id:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/>
                        <TextBox x:Name="idTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="0" Text="{Binding Id, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
                        <Label Content="Name:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="1" VerticalAlignment="Center"/>
                        <TextBox x:Name="nameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="1" Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
                        <Label Content="Tournaments:" HorizontalAlignment="Left" Margin="3" Grid.Row="2" VerticalAlignment="Center"/>
                        <ListBox x:Name="tournamentsListView" ItemsSource="{Binding Source={StaticResource groupTournamentsViewSource}}" Margin="3,3,-182,-260" SelectionMode="Multiple" Grid.Row="2" Grid.Column="1">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <EventSetter Event="UIElement.PreviewMouseRightButtonDown" Handler="EmptyHandler"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="Add To Selected Tournaments" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=PlacementTarget.DataContext.AddTournamentCommand}"/>
                                </ContextMenu>
                            </ListBox.ContextMenu>
                        </ListBox>
                    </Grid>
                </Grid>
            </TabItem>
            <TabItem Header="Tournaments">
                <Grid Background="#FFE5E5E5" Margin="0,0,0,-2">
                    <ListBox HorizontalAlignment="Left" Margin="10,10,0,10" Width="166"/>
                </Grid>
            </TabItem>
            <TabItem Header="Teams">
            </TabItem>
            <Grid Margin="0,0,-10,10"/>
        </TabControl>

    </Grid>
</Window>

and in the Code Behind:

public partial class MainWindow : Window
{
    [removed]

    private ICommand addTournamentCommand;
    public ICommand AddTournamentCommand
    {
        get
        {
            if(addTournamentCommand == null)
            {
                addTournamentCommand = new RelayCommand(OnTournamentAdded);
            }

            return addTournamentCommand;
        }
    }

    private void OnTournamentAdded(object state)
    {

    }
}

PlacementTarget property is on Context Menu and not on window. Travel to ContextMenu and not to Window. Window anyhow doesn't lies in Visual Tree of ContextMenu so you can't reach to it using RelativeSource.

<ContextMenu>
   <MenuItem Header="Add To Selected Tournaments"
             Command="{Binding RelativeSource={RelativeSource
                               AncestorType={x:Type ContextMenu}},
                        Path=PlacementTarget.DataContext.AddTournamentCommand}"/>
</ContextMenu>

With above code you will get PlacementTarget's dataContext which will be ListBox's DataContext and if you haven't set explicitly DataContext on ListBox, it will inherit it from Window and your code will work fine.


UPDATE

You can store the Window DataContext in Tag of ListBox and bind with it .

<ListBox Tag="{Binding DataContext,
               RelativeSource={RealtiveSource Mode=FindAncestor, 
                              AncestorType=Window}}"/>

and in ContextMenu bind using Tag:

<ContextMenu>
   <MenuItem Header="Add To Selected Tournaments"
             Command="{Binding RelativeSource={RelativeSource
                               AncestorType={x:Type ContextMenu}},
                        Path=PlacementTarget.Tag.AddTournamentCommand}"/>
</ContextMenu>

Change like this,

 <ContextMenu>
    <MenuItem Header="Add To Selected Tournaments" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=AddTournamentCommand}"/>
  </ContextMenu>

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