WPF Datagrid ContextMenu SelectedItem - c#

I have the following problem.
I have a DataGrid with a ContextMenu. But when the Command is triggered the SelectedItem is always null. Any recommendations?
Thats my ContextMenu:
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding OpenFileCommand}"
CommandParameter="{Binding Path=SelectedItem,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Header="open file" />
i also tried:
CommandParameter="{Binding ElementName=nameOfGrid, Path=SelectedItem}"

Thanks for your help. I fixed it this way: CommandParameter="{Binding PlacementTarget.SelectedItem,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ContextMenu}}}"

I think your answer is here: CommandParameters in ContextMenu in WPF
Another better option imho is to keep "SelectedItem" binded in your ViewModel.
Then you don't need a command parameter anymore, and you can juste use the SelectedItem binded from your ViewModel.

The problem is that the ContextMenu is in a different VisualTree.
You could use the Tag for binding the Command. See the following link

Related

WPF Binding CommandParameter to Element of perent window

I build some WPF application that as MainView, inside this MainView I have a button that opens a setting window and a Model that I want to be able to show or hide from this settings view. (the show/hide button was originally on the MainView itself) the problem is that I do not know how to use the CommandParameter in the SettingsView to bind to an element In the MainViw.
the element in the MainView:
<Dev:DevUnitView x:Name="DevData" DataContext="{Binding MainModel.DevUnit}" Visibility="Visible" Margin="994,656,74,-83"/>
the button in the SettingsView:
<Button Content="Show/Hide debug values" Command="{Binding Settings.DevVisibilityCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Dev:DevUnitView}}, Path=DataContext}" Margin="156,22,180,349"/>
I also tried to Bind to the MainView but I do not know how to find the element I need from there:
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type mainWindow:MainView}}, Path=DevUnit}"
in this case, it cannot resolve the "DevUnit" in the data context, I also tried by name and other variation of this without success.
the old button that worked in the MainView:
<Button Content="DEV" Command="{Binding Settings.DevVisibilityCommand}" CommandParameter="{Binding ElementName=DevData}" Margin="406,359,810,259"/>
now no matter how I try to bind it I getting Null UserControl.

Why is my CommandParameter null when I have the Path as SelectedItem?

So I am trying to pass the SelectedItem as a parameter so that I can make use of the data that is bound to it.
Essentially I want to open a MessageBox and display the Name property of the User that is bound that item.
This is my xaml
<ItemsControl ItemsSource="{Binding CardViewModel.Users}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultEffectDataTemplate="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserCard>
<controls:UserCard.ContextMenu>
<!-- Bind the DataContext of the CM to the DataContext that's bound to the RootObject-->
<ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
<MenuItem Header="Edit"
Command="{Binding CardViewModel.EditUser}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.SelectedItem}"/>
</ContextMenu>
</controls:UserCard.ContextMenu>
</controls:UserCard>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The command works fine everything is bound just fine besides that when I click the MenuItem and it fires the command, I put a breakpoint where the action is and it shows the parameter as null I am suspecting that it's me who is binding it wrong.
public void DisplayEditUser(object user)
{
if (user != null)
{
MessageBox.Show("Not null");
}
}
The problem is that ContextMenu.PlacementTarget wasn't the ItemsControl but the UserCard, so binding source resolving will absolutely fail. To solve it, you need to bind ItemsControl.SelectedItem to one property of UserCard such as Tag as a relay.
<controls:UserCard Tag="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=ListBox}}">
CommandParameter="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"

Getting selected menuitem when it is dynamically created

I've got a ContextMenu that looks like this:
<ContextMenu StaysOpen="False" Width="150" x:Name="HistoryContextMenu">
<MenuItem Command="{Binding HistorySetCurrent}" Header="Set _Current (C)"/>
<MenuItem Command="{Binding HistorySetReference}" Header="Set _Reference (R)" />
<MenuItem Header="Add to Group" ItemsSource="{Binding ElementName=Groups, Path=ChartGroups}" DisplayMemberPath="Name" HorizontalAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<cmd:EventToCommand Command="{Binding HistoryGroupContextClickCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=MenuItem}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
I'm using MVVM so I'm binding to a method to handle the PreviewMouseUp event (I have tried other events too). I get a list in my submenu as wanted, but when I click on one of them, the eventargs I get contain all the menu items in the list, not just the one I selected, with no incdication of the one chosen.
How do I find the selected menuitem? I've tried doing this with code behind, but the same problem occurs with that method too.
You should use an ItemContainerStyle to manage the Commands on the generated MenuItems.
Have a look at Kent's answer to this question which shows you how to setup the style: Using a DataTemplate for a MenuItem causes extra space on the left side to appear?
You would need to add the binding for the Command and the individual item as the CommandParameter in order to have context for the Command to run against.

Cannot bind command within a ListBox

My WPF uses the MVVM approach. I'm trying to bind 2 controls within my list control
<ListBox ItemsSource="{Binding ParentDuplicate}" SelectedItem="{Binding SelectedParent, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentControl Content="{Binding}" />
<Button Content="Delete me now"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}, Path=DeleteCommand}"
CommandParameter="{Binding FilePath}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem I'm having, is the DeleteCommand is not binding (the Ouput window informs me as well)
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Data.Binding', AncestorLevel='1''. BindingExpression:Path=DeleteCommand; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
If I move this button to outside the ListBox, then the binding works and the event fires so I know the issue must be with the ListBox (I'm guessing the problem is the ItemsSource prevents the binding to anything but the ItemsSource bound property (in this case, ParentDuplicate))
So, within the Button control, there are 2 properties being bound, DeleteCommand and FilePath
Both of these properties live within my single ViewModel. FilePath is a child of ParentDuplicate and this binds as desired. The issue is only with the DeleteCommand. What am I doing wrong?
Edit
When I use the Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}, Path=DeleteCommand} it is looking in my MainWindow code behind, not at the ViewModel. How do I make it use the ViewModel?
I tried
Command="{Binding RelativeSource={RelativeSource AncestorType=xmlnsViewModel:MainWindowViewModel}, Path=DeleteCommand}"
but the above also results in the same binding errors
The ancestor search finds the control, not the DataContext, so you'll need to tell your binding where to find the DeleteCommand property. If your ViewModel is the DataContext of the MainWindow then you can just use:
<Button Content="Delete me now"
Command="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorLevel=1, AncestorType=Window},
Path=DataContext.DeleteCommand}"
CommandParameter="{Binding FilePath}" />

WPF parent child relation in binding

I am working on an application which is totally based on MVVM. I am facing a binding problem.
<ListView ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.CurrentSecurityList}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Command="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.RemoveSecurity}"/>
</ContextMenu>
</ListView.ContextMenu>
ListView binding is working absolutely fine in this code but the problem comes when it comes to MenuItem Command Binding. Can someone explain what i am doing wrong over here.
Put a Tag in ListView to connect its ancestor to its ContextMenu:
<ListView ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.CurrentSecurityList}"
Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Command="{Binding PlacementTarget.Tag.DataContext.RemoveSecurity, RelativeSource={RelativeSource
AncestorType=ContextMenu}}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
ContextMenu works on different visual tree so it is not possible to bind it like that. You need to find ContextMenu ancestor and refer to its PlacementTarget.DataContext to retrieve your command. Try something like this:
<MenuItem Header="Remove" Command="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ContextMenu}},Path=PlacementTarget.DataContext.RemoveSecurity}"/>

Categories