Reputation: 554
Is it possible to bind the CommandParameter for a ListBox ContextMenu to the Selected Item of the ListBox? I should say that the ContCommand is in the main window and it is called when the Context Menu item is clicked - however, I need to get the parameter to work properly.
I tried this but the binding fails:
<Window x:Class="ListBoxContextMenu.MainWindow"
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:local="clr-namespace:ListBoxContextMenu"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<TextBlock Text="ListBox here:"/>
<ListBox ItemsSource="{Binding Items}" MinHeight="100" TabIndex="0" x:Name="LB">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Foo" Command="{Binding ContCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}},Path=SelectedItem}"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</StackPanel>
</Grid>
</Window>
C# code for MainWindow:
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using MvvmFoundation.Wpf;
namespace ListBoxContextMenu
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Loaded += (sender, e) => MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
ContCommand = new RelayCommand<object>((object o) =>
{
System.Diagnostics.Debug.WriteLine("Context Menu pressed");
});
}
public ObservableCollection<string> Items { get; set; } = new ObservableCollection<string>{"Fred", "Jim", "Sheila"};
public RelayCommand<object> ContCommand { get; set; }
}
}
Upvotes: 4
Views: 6570
Reputation: 1382
instead of binding it to the listbox bind it to the listboxitem that have been clicked he is the concerned !! not the listbox he hold the object that you are seeking
<ListBox x:Name="lstAllTags" FocusVisualStyle="{x:Null}" ItemsSource="{Binding ResearchedTagsResult}" Margin="0" Background="{x:Null}" BorderBrush="{x:Null}" ItemTemplate="{DynamicResource SearchTagDataTemplate}" FontFamily="Consolas" Foreground="{DynamicResource {x:Static SystemColors.InfoBrushKey}}" MouseMove="LstAllTags_MouseMove" MouseLeave="LstAllTags_MouseLeave" HorizontalContentAlignment="Stretch" Focusable="False" FontSize="13" SelectionChanged="LstTags_SelectionChanged" BorderThickness="0">
<ListBox.Resources>
<!--Defines a context menu-->
<ContextMenu x:Key="ContextMenu">
<MenuItem Command="{Binding DeleteTagCmd }" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=DataContext}" Foreground="{DynamicResource AppTextForeground}" DataContext="{DynamicResource TagManagement_instance}" Header="Edit" BorderBrush="#FF919191" BorderThickness="0" Padding="0">
<MenuItem.Icon>
<Image Source="/Resx/pencil.png"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.Resources>
</ListBox>
Upvotes: 0
Reputation: 169420
The ListBox
is not a visual ancestor of the ContextMenu
because the latter resides in its own visual tree.
But you could bind to the PlacementTarget
of the ContextMenu
, which is the ListBox
.
This works:
<ListBox ItemsSource="{Binding Items}" MinHeight="100" TabIndex="0" x:Name="LB">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Foo" Command="{Binding ContCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.SelectedItem}"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Upvotes: 16
Reputation: 31721
The context menu is on a different tree and so binding is tricky depending on the situation. Here are two options:
1 Bind to the listbox via its name such as
Binding SelectedItem, ElementName=LB
2 Use the reference name
Sometimes an element name binding fails and one has to use the x:ref name (which you have)
Binding Source={x:Reference LB}, Path=SelectedItem
As to the why, to quote x:Reference
In WPF and XAML 2006, element references are addressed by the framework-level feature of ElementName binding. For most WPF applications and scenarios, ElementName binding should still be used. Exceptions to this general guidance might include cases where there are data context or other scoping considerations that make data binding impractical and where markup compilation is not involved.
Upvotes: 1
Reputation: 1118
Add Mode=FindAncestor
to the RelativeSource
binding.
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, Path=SelectedItem}"
Upvotes: 0