0

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)
    {

    }
}
Kyle W
  • 3,702
  • 20
  • 32

2 Answers2

2

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>
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • If you look in the XAML, the ListBox does have a different DataContext. How would I bypass that, or get the command on that context? It's bound to an object model, so I'm hesitant to put a Command object on it. – Kyle W Mar 24 '14 at 22:29
  • That did solve the binding issues. I still couldn't get the action to trigger, so I ended up just making a button to keep from making myself overly frustrated. – Kyle W Mar 27 '14 at 02:40
0

Change like this,

 <ContextMenu>
    <MenuItem Header="Add To Selected Tournaments" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=AddTournamentCommand}"/>
  </ContextMenu>
Sankarann
  • 2,625
  • 4
  • 22
  • 59
  • But a Window isn't in the tree, right? This doesn't bind. Gives me: Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=AddTournamentCommand; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand') – Kyle W Mar 24 '14 at 22:27