I have an application that displays a list of ViewModels as tab control items. The list of items is databound to a property on the parent ViewModel. Now I want to add a context menu to support actions for each of the TabItems (not the whole TabControl itself).
This is the control in question:
<TabControl x:Name="Items"
Grid.Column="2"
Grid.Row="0"
Margin="3,5,5,3"
Visibility="{Binding Path=TabControlVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DisplayName}" />
<Button Padding="10,0,0,0"
Content="X"
Style="{DynamicResource NoChromeButton}"
cal:Message.Attach="CloseTab($dataContext)" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
When I put the context menu code inside the TabControl tags the context menu iis registered for the TabControl as a whole. This is not the behaviour I want.
If I add it to the StackPanel tags inside the DataTemplate Tags, the DataTriggers registered for each Item is getting executed on the child ViewModel, but the view model does not have the methods and properties to execute the event.
Is there a possibility to solve this problem? How can I add a context menu to each item to support actions like: "Close This", "Save This", "Close Everything Except This"
Some more Infos:
I use Caliburn.Micro as framework and use it's conventions to bind the TabControl to the Items property on the ViewModel, which is an IObservableCollection<LocationDetailsViewModel> created by inheriting my ViewModel from Conductor<LocationDetailsViewModel>.Collection.OneActive. The LocationsDetailsViewModel also inherits from Screen
Everything works as intended. If I add an item to the Items property the TabControl gets updated properly.
I want to add a ContextMenu to each TabControl item, which is accessible by right-clicking the header. The context menu then should contain actions, like "Close This", "Save This", "Close Everything Except This"
For that I added a context menu to the StackPanel which controls the design of the header and used CM to call the appropriate method on the view model. But when I call it, I get an exception telling me that no suitable method can be found.
I double checked and it seems CM wants to call a method on the LocationDetailsViewModel and not the LocationViewModel, even though a similar method call exist in the close button for each tab item.
Here is the code with the context menu:
<UserControl x:Class="RpgTools.LocationPresenter.Views.LocationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:vm="clr-namespace:RpgTools.LocationPresenter.ViewModels"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=vm:LocationViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True"
Padding="5">
<!-- Code left out for brevity -->
<TabControl x:Name="Items"
Grid.Column="2"
Grid.Row="0"
Margin="3,5,5,3"
Visibility="{Binding Path=TabControlVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Close This"
cal:Message.Attach="CloseTab($dataContext)">
</MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding DisplayName}" />
<Button Padding="10,0,0,0"
Content="X"
Style="{DynamicResource NoChromeButton}"
cal:Message.Attach="CloseTab($dataContext)" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
MethodNotFoundexception is thrown. - Ruhrpottpatriot