In Button Click Context Menu How do I bind to viewModel? - c#

I have a button on click on that button opening a context menu, now clicking on the context menus is to be binded to viewModel. But its not happening.
<Button Content="Copy" Tag="{Binding LinkViewModel, RelativeSource={RelativeSource Mode=Self}}" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Download link " Command="{Binding Path=Parent.PlacementTarget.Tag.CopyViewCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
</Button>
I have tried the tag property but it seems to me that its not working. The viewmodel is working fine if I bind to the button itself, but the contextMenu dataBinding is not working.
EDIT:
Now as the code is working after discussion, I think to post it here.
What the changes I made is I put UpdateSourceTrigger="Propertychanged" here is the code
<Button Content="Copy" Tag="{Binding LinkViewModel, RelativeSource={RelativeSource Mode=Self}}" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu Width="{Binding RelativeSource={RelativeSource Self}}">
<MenuItem Header="Copy View link " Command="{Binding CopyViewCommand, UpdateSourceTrigger=PropertyChanged}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
</Button>
However I don't know how come suddenly it works, it has to work with tag property in case of Button Context menu. If anybody put some light into this I think many people like me who are new WPF and data binding will be benefited.

I'm assuming you are using this Button inside the UserControl. Please try below code
<Button Content="Copy" Tag="{Binding LinkViewModel, RelativeSource={RelativeSource Mode=Self}}" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Download link " Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.CopyViewCommand}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
</Button>

<Button Content="Copy" Command="{Binding LinkCopyCommand, UpdateSourceTrigger=PropertyChanged}" >
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy Download link " Command="{Binding Path=CopyViewCommand}" />
<MenuItem ... />
</ContextMenu>
</Button.ContextMenu>
CopyViewCommand Bound directly from your DataContext... which is your ViewModel..

You have to setyour ContextMenu's DataContext to your ViewModel. One way to do this is by having an Opened eventhandler for the context menu.
Take a look at my answer in the below link -
Context Menu items command binding WPF using MVVM

Related

Avalonia .xaml can't go to definition, F12 also don't work, why?

<editor:DrawingNode.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Cu_t" Command="{Binding CutCommand}" InputGesture="Ctrl+X" />
<MenuItem Header="_Copy" Command="{Binding CopyCommand}" InputGesture="Ctrl+C" />
<MenuItem Header="_Paste" Command="{Binding PasteCommand}" InputGesture="Ctrl+V" />
<MenuItem Header="_Delete" Command="{Binding DeleteCommand}" InputGesture="Delete" />
<MenuItem Header="-" />
<MenuItem Header="Select _All" Command="{Binding SelectAllCommand, FallbackValue={x:Null}}" InputGesture="Ctrl+A" />
<MenuItem Header="De_select All" Command="{Binding DeselectAllCommand, FallbackValue={x:Null}}" InputGesture="Escape" />
</MenuFlyout>
</editor:DrawingNode.ContextFlyout>
I want to go to the definition of cut command, but pressing F12 did not go to the definition/source of avalonia. Does avalonia support navigation to the definition of their elements in xaml?

Bind ContextMenu Item inside Button to ViewModel

I'm trying to add a ContextMenu with an ItemMenu to a button
<Button x:Name="RemoteMachine" Command="{Binding ElementName=RemoteMachines, Path=DataContext.RemoteMachineSelectedCommand}" CommandParameter="{Binding}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" CommandParameter="{Binding}"
Command="{Binding ElementName=RemoteMachines, Path=DataContext.DeleteRemoteMachineCommand}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
In my model I have the following
public ICommand RemoteMachineSelectedCommand => new CommandHandler(p => MachineSelectedAction(p, true), true);
public ICommand DeleteRemoteMachineCommand => new CommandHandler(p => DeleteRemoteMachineAction(p), true);
The Button command works correctly while the ContextMenu one doesn't.
I suppose I'm binding it someway wrong.
Any suggestion?
You could bind the Tag property of the Button to the command and then bind to it from the MenuItem using the PlacementTarget property of the parent ContextMenu:
<Button x:Name="RemoteMachine"
Tag="{Binding ElementName=RemoteMachines, Path=DataContext.DeleteRemoteMachineCommand}"
Command="{Binding ElementName=RemoteMachines, Path=DataContext.RemoteMachineSelectedCommand}"
CommandParameter="{Binding}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete"
CommandParameter="{Binding PlacementTarget.CommandParameter,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"
Command="{Binding PlacementTarget.Tag,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>

Bind ContextMenuItem Property to a DataGrid or an other Element Property

I trying to bind ContextMenuItem property to a DataGrid Property as flow:
<DataGrid Name="DG_Data" >
<DataGrid.Columns>
<DataGridTextColumn Header="COL1"/>
<DataGridTextColumn Header="COL2"/>
<DataGridTextColumn Header="COL3"/>
<DataGridTextColumn Header="COL4"/>
</DataGrid.Columns>
</DataGrid>
<Button Name="BTN_OpenContext" Content="CLICK TO OPEN">
<Button.ContextMenu>
<ContextMenu Name="CM_ContextMenu">
<MenuItem Header="{Binding ElementName=DG_Data,Path=Columns.Count,FallbackValue=BindingFailed}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
I have tried also using the different way with RelativeSource
<MenuItem Header="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=2,AncestorType=FrameworkElement}, FallbackValue=BindingFailed}" />
I have just be able to bind to the parent (the ContextMenu).
Thanks
The ContextMenu can't bind to the DataGrid using ElementName, but it can't bind to a property of the parent ContextMenu's PlacementTarget (which is the Button).
So you could bind the Button's Tag property to the DataGrid, and then bind to the Tag property from the MenuItem:
<Button Name="BTN_OpenContext" Content="CLICK TO OPEN"
Tag="{Binding ElementName=DG_Data}">
<Button.ContextMenu>
<ContextMenu Name="CM_ContextMenu">
<MenuItem Header="{Binding Path=PlacementTarget.Tag.Columns.Count,
RelativeSource={RelativeSource AncestorType=ContextMenu}, FallbackValue=BindingFailed}" />
</ContextMenu>
</Button.ContextMenu>
</Button>

WPF, TreeViewItem, how to not show contextMenu according to dependency property?

I have a treeview using the following style:
<HierarchicalDataTemplate x:Key="itemTemplate" DataType="{x:Type AttCatalog:AttachmentCatalogModel}" ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" Tag="{Binding Guid}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="New Item"/>
<MenuItem Header="Move to..." />
<MenuItem Header="Delete" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</HierarchicalDataTemplate>
<TreeView x:Name="tree" HorizontalAlignment="Left" Width="216" BorderThickness="0,0,1,0" Background="#FFFBFBFB" IsEnabled="{Binding IsEnabled}" ItemsSource="{Binding Catalogs}" ItemTemplate="{StaticResource itemTemplate}" TreeViewItem.Expanded="OnExpandItemHandler" Margin="0,0,0,241" SelectedItemChanged="tree_SelectedItemChanged">
you can see TextBlock Tag binding a Guid property, my question is, how to do that when this Guid is empty (00000-00000000-00000), not show the contextMenu?
In your context menu, bind the visibility to the Guid, and treat it with a converter =>
<ContextMenu Visibility="{Binding Element=Guid,
Converter={StaticResource GuidToVisibilityConverter}}">
<MenuItem Header="New Item"/>
<MenuItem Header="Move to..." />
<MenuItem Header="Delete" />
</ContextMenu>
In your converter, you can treat your Guid value the way you want, to either return Visibility.Visible or Visibility.Hidden, depending on the value.
You can find more information on converters here.
Hope that helped !

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