问题
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??
回答1:
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.
回答2:
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