ListView TextBlock context menu is not invoking the bound command - wpf

My ListView is binded to ObservableDictionary source. In ListView control, value is bound to TextBlock. The context menu for TextBlock is bound to an event but the event is not being executed on click. Below is the code.
<ListView ItemsSource="{Binding Path=Source, Mode=TwoWay}" Grid.Row="0" Height="300">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Value}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path= MenuClicked}" CommandParameter="Delete"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
<MenuItem Header="Rename">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path= MenuClicked}" CommandParameter="Rename"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path= MenuClicked}" CommandParameter="Add"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
<MenuItem Header="Import">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path= MenuClicked}" CommandParameter="Import"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</ListView.ContextMenu>
</ListView>

Try to provide a RelativeSource for your CommandBinding. Something like
<i:InvokeCommandAction Command="{Binding Path=DataContext.MenuClicked, RelativeSource={RelativeSource.FindAncestor, AncestorType=Window}}" CommandParameter="Delete"/>
Replace the AncestoryType=Window with AncestoryType=UserControl if your ListView is inside a UserControl

ContextMenu doesn't get same NameScope as in the UIElement they are defined.
So binding (like ElementName, Ancestor) usually creates the problem. You have to set Name scope first in the code behind:
NameScope.SetNameScope(contextMenu, NameScope.GetNameScope(this));
contextMenu is the x:Name of your context menu.
Then you can use relative source binding or any other binding for command. like below:
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x: type ListView}},Path=DataContext.MenuClicked}"
PS: If MenuClicked command is defined in the DataContext of ListView.

Related

a ActionMessage EventTrigger for ItemDataTemplate

I have a question for ItemsControl.
If I wan't to Bind the Func Out of Items, like this:
Code:
<Button cal:Action.TargetWithoutContext="{Binding MenuItemX}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="Clicked" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Link:((Caliburn Micro) Mapping a ActionMessage Methodname to a Child Object of the ViewModel).
But I Bind the TreeView DataTemplate and use a Control MouseClick:
Code:
<HierarchicalDataTemplate x:Key="treeDataTemplate" DataType="{x:Type myData:Music}" ItemsSource="{Binding ChildNode}">
<TextBlock Text="{Binding Name}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<cal:ActionMessage MethodName="TreeItemClick" >
<cal:Parameter Value="{Binding}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</HierarchicalDataTemplate>
The problem here is that the TextBlock(in Child ViewModel), the MethodName(in MainViewModel), and the Parameter(in Child ViewModel).
What's the best way to build it?

CommandParameter with MVVM Light

I'm trying to get a RelayCommand working with a CommandParameter working using MVVM Light. The command is defined in my viewmodel, and I want to pass the selected ListBox item as the parameter. The command is bound, but the parameter is not. Is this possible?
<UserControl x:Class="Nuggets.Metro.Views.EmployeeListView"
...
DataContext="{Binding EmployeeList,Source={StaticResource Locator}}">
<ListBox x:Name="lstEmployee" ItemsSource="{Binding EmployeeItems}" Style="{StaticResource EmployeeList}" Tag="{Binding EmployeeItems}">
<ListBox.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit item" Command="{Binding EditEmployeeCommand}" CommandParameter="{Binding PlacementTarget.SelectedItem,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
<MenuItem Header="Delete item" Command="{Binding DeleteEmployeeCommand}" CommandParameter="{Binding PlacementTarget.SelectedItem,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
</ContextMenu>
</ListBox.ContextMenu>
This should work
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit item"
Command="{Binding EditEmployeeCommand}"
CommandParameter="{Binding SelectedItem,ElementName=lstEmployee}"/>
<MenuItem Header="Delete item"
Command="{Binding DeleteEmployeeCommand}"
CommandParameter="{Binding SelectedItem,ElementName=lstEmployee}"/>
</ContextMenu>
Use the Name of your ListBox als ElementName in the binding of the CommandParameter and set the path to SelectedItem.
Update:
The above code does not work for ListBox and ContextMenu, cause they belong to diffrent visual trees. The result is
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=lstEmployee'. BindingExpression:Path=SelectedItem; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'CommandParameter' (type 'Object')
The following XAML does the job. Using the PlacementTarget (that is the ListBox) of the ContextMenu.
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit item"
Command="{Binding EditEmployeeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"/>
<MenuItem Header="Delete item"
Command="{Binding DeleteEmployeeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"/>
</ContextMenu>
This works for TreeView or ListView with MVVM.
The PlacementTarget from the ContextMenu is (here) the Listview
<ListView.ContextMenu>
<ContextMenu>
<MenuItem x:Name="OpenExplorer"Header="ShowFolder"
Command="{Binding ShowExplorer}"
CommandParameter ="{Binding Path=PlacementTarget.SelectedItem,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</ListView.ContextMenu>

silverlight combobox invokecommandaction on selectionchanged event cannot pass parameter

I have a combobox, using databinding and MVVM pattern. Everytime the user changes the selection, I added an event trigger, and a command is executed. the code is the following:
<ComboBox x:Name="myComboBox" Width="150" ItemsSource="{Binding Items}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LoadCommand}" CommandParameter="{Binding SelectedItem, ElementName=myComboBox}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
the problem is that the parameter it passes is always null.
I changed the parameter from SelectedItem to SelectedIndex, this way I get the parameter and it is not null. Then i get my object using the index.

RadTreeViewItem, MVVM, and Click events

I'm having trouble getting a click event or mouse down event to fire on a RadTreeViewItem in the ViewModel. What syntax should I be using? This is the relevant XAML below:
<Toolkit:AccordionItem x:Name="Accordion1" Header="{Binding Header, Mode=TwoWay}" Width="200">
<ListBox x:Name="SitesList" Width="195" BorderThickness="0" ItemsSource="{Binding Games, Mode=OneWay}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<telerik:RadTreeView IsDragDropEnabled="True" IsSingleExpandPath="True"
telerikDragDrop:RadDragAndDropManager.AllowDrag="True" PreviewDragEnded="RadTreeView_PreviewDragEnded"
IsDragTooltipEnabled="False">
<telerik:RadTreeViewItem Header="{Binding siteName, Mode=TwoWay}" Tag="{Binding siteKey, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding RadTreeItemClickCommand, Mode=TwoWay}" MustToggleIsEnabledValue="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadTreeViewItem>
</telerik:RadTreeView>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Toolkit:AccordionItem>
As far as I can tell, binding the events of the RadTreeViewItem has to be done in code-behind; the ItemPrepared event of RadTreeView is fired when a RadTreeViewItem is created and bindings can be set in a handler. More information here:
http://www.telerik.com/help/silverlight/radtreeview-events-working-with-item-prepared-event.html
Don't bother with the event to command. You can set a command on the RadTreeViewItem directly.

how to send id of button clicked to command?

I've got a button inside a datatemplate. When the button is clicked I'd like to send the id of the button to my command. The snippet below obviously dosn't work. What am i doing wrong?
<DataTemplate>
<Button CommandParameter="ProductId" x:Name="btnProduct" Width="180" Height="40" Content="{Binding DisplayText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<n:ExecuteCommandAction Command="{Binding ShowSandwichPriceCommand}"
Parameter="{Binding ElementName=btnProduct, Path=SelectedValue}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
The button element doesn't have the SelectedValue property.
You might want to use the Name propery instead or some other available property.
<DataTemplate>
<Button CommandParameter="ProductId" x:Name="btnProduct" Width="180" Height="40" Content="{Binding DisplayText}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<n:ExecuteCommandAction Command="{Binding ShowSandwichPriceCommand}"
Parameter="{Binding ElementName=btnProduct, Path=Name}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
Hope this helps
i was able to get my code working with this. thanks.
<DataTemplate>
<Button Command="{Binding DataContext.ShowSandwichPriceCommand, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding Path=ProductId}"
Content="{Binding DisplayText}">
</Button>
</DataTemplate>

Resources