I'm trying to get a context menu within a ListBox ItemTemplate to call a method on the parent view model, passing in the item that was clicked on as a parameter. I have this working for other buttons in the item template, but for the context menu it seems to be failing.
I have the following xaml (abbreviated for clarity):
<ListBox>
<ListBox.GroupStyle>
<GroupStyle>
...
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ContextMenu>
<ContextMenu Name="cm">
<MenuItem Header="Open"
cal:Message.Attach="Open($dataContext)">
</MenuItem>
</Grid.ContextMenu>
<TextBlock VerticalAlignment="Center" >
.. text..
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have a feeling this has to do with the fact that the visual tree is different, so Caliburn is unable to resolve the method reliably. I'm sure this is a common problem, and I've tried a few of the things I've found online, but nothing seems to be working.
Any ideas??
Using the information I found on the Caliburn Micro site I modified your XAML to look like this:
<Grid Background="White" HorizontalAlignment="Stretch" Height="200" Name="GridLayout">
<ListBox x:Name="ListBoxItems">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Tag="{Binding DataContext, ElementName=GridLayout}">
<Grid.ContextMenu>
<ContextMenu Name="cm" cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Open"
cal:Message.Attach="Open($dataContext)">
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
<TextBlock VerticalAlignment="Center" >
.. text..
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
And my view model:
public List<string> ListBoxItems { get; set; }
public ShellViewModel()
{
ListBoxItems = new List<string> {"One", "Two", "Three"};
}
public void Open(object source)
{
MessageBox.Show((string) source);
}
Open was successfully called with the appropriate strings from the list box.
Adding to Jason's answer, if you're going to be using the same data context as the control, then you can just bind the DataContext
instead of a Tag
<Grid>
<Grid.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Open"
cal:Message.Attach="Open($source)">
</MenuItem>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
$source
The actual FrameworkElement that triggered the ActionMessage to be
You can see more info about the $source
convention in here: https://caliburnmicro.com/documentation/cheat-sheet
来源:https://stackoverflow.com/questions/10126797/wpf-context-menus-in-caliburn-micro