I try to get my foot on the ground with WPF and MVVM for almost a year now but every time I think I understood how it's working or at least how it's supposed to work, something comes up that's not working and I can't understand or figure out why. Maybe you can help me with this one.
For the sake of simplicity I have a very basic ViewModel:
Public Class MainViewModel
Private _testCommand As ICommand = New RelayCommand(AddressOf Me.Test)
Private _items As IEnumerable(Of String) = New String() {"Item 1", "Item 2", "Item 3"}
Public ReadOnly Property TestCommand As ICommand
Get
Return _testCommand
End Get
End Property
Private Sub Test()
MsgBox("Test")
End Sub
Public ReadOnly Property Items As IEnumerable(Of String)
Get
Return _items
End Get
End Property
End Class
This view model I use as DataContext for my equally basic window with two ListView
s.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ContextMenuTest"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Window.Resources>
<ContextMenu x:Key="ItemContextMenu">
<MenuItem Header="Test Left" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.TestCommand}" />
</ContextMenu>
<Style x:Key="TestItemStyle_Left" TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
</Style>
<Style x:Key="TestItemStyle_Right" TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Test Right" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.TestCommand}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView Grid.Column="0" ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource TestItemStyle_Left}">
<ListView.View>
<GridView>
<GridViewColumn Header="Test" Width="100" DisplayMemberBinding="{Binding}" />
</GridView>
</ListView.View>
</ListView>
<ListView Grid.Column="1" ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource TestItemStyle_Right}">
<ListView.View>
<GridView>
<GridViewColumn Header="Test" Width="100" DisplayMemberBinding="{Binding}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Both ListView
s are the same, they only differ in the ItemContainerStyle
they use.
And both ItemContainerStyle
s only differ in the way the ContextMenu
is worked in. On the left side it's implemented and used as a resource, on the right side it's implemented directly.
But why does the command binding of the context menu item only work on the left side and not on the right side?
Thank you for your explanations :-)