I am using the mvvm pattern and I am having a hard time figuring out how to set the DataContext on a ContextMenu from inside a ListView’s ItemContainerStyle.
I also do not understand why the ListView.ContextMenu and the ListView’s GridView.ColumnHeaderContextMenu can see the properties and commands from my view model, but the ContextMenu inside the ListView.ItemContainerStyle cannot.
Error
System.Windows.Data Error: 40 : BindingExpression path error: 'AddMenuItem' property not found on 'object' ''Currency' (HashCode=43406546)'. BindingExpression:Path=AddMenuItem; DataItem='Currency' (HashCode=43406546); target element is 'ContextMenu' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
View
<!-- Removed styles for clarity. -->
<UserControl>
<!-- Add ElementSpy to the UserControl’s rsources -->
<UserControl.Resources>
<framework:ElementSpy x:Key="spy" />
</UserControl.Resources>
<ListView ItemsSource="{Binding Currency}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="ContextMenu">
<Setter.Value>
<!-- 'AddMenuItem' property not found on 'object' 'Currency' -->
<!-- ContextMenu ItemsSource="{Binding AddMenuItem}" / -->
<!-- Use the ElementSpy resource -->
<ContextMenu ItemsSource="{Binding Source={StaticResource spy}, Path=Element.DataContext.AddMenuItem}" />
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ContextMenu>
<!-- Works -->
<ContextMenu ItemsSource="{Binding EditMenuItem}" />
</ListView.ContextMenu>
<ListView.View>
<GridView>
<GridView.ColumnHeaderContextMenu>
<!-- Works -->
<ContextMenu ItemsSource="{Binding SortMenuItem}" />
</GridView.ColumnHeaderContextMenu>
<GridViewColumn Header="Code"
DisplayMemberBinding="{Binding Path=Code}" />
<GridViewColumn Header="Description"
DisplayMemberBinding="{Binding Path=Description}" />
<GridViewColumn Header="Exchange Rate"
DisplayMemberBinding="{Binding Path=ExchangeRate}" />
</GridView>
</ListView.View>
</ListView>
</UserControl>
Code Behind
[Export(ViewNames.CurrencyMasterView, typeof(IMasterView))]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class CurrencyMasterView
: UserControl, IMasterView
{
public CurrencyMasterView()
{
InitializeComponent();
}
[Import]
private MasterViewModel ViewModel
{
set
{
this.DataContext = value;
}
}
}
ViewModel
[Export(typeof(MasterViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class MasterViewModel
: ViewModelBase
{
[ImportingConstructor]
public MasterViewModel(IGeneralController generalController, IRegionManager regionManager)
{
}
public ObservableCollection<Currency> Currency
{
get
{
return this.currency;
}
set
{
if (this.currency != value)
{
this.currency = value;
this.RaisePropertyChanged(() => this.Currency);
}
}
}
public List<MenuItemMvvm> SortMenuItem
{
get
{
return this.CreateSortMenuItem();
}
}
public List<MenuItemMvvm> EditMenuItem
{
get
{
return this.CreateEditMenuItem();
}
}
public List<MenuItemMvvm> AddMenuItem
{
get
{
return this.CreateAddMenuItem();
}
}
private List<MenuItemMvvm> CreateEditMenuItem()
{
var menu = new List<MenuItemMvvm>();
menu.Add(new MenuItemMvvm("_Edit")
{
Command = this.EditCommand,
Icon = new Image
{
Source = new BitmapImage(new Uri("pack://application:,,,/POS.Modules.Core;component/Resources/Images/16X16/Edit.png"))
}
});
menu.Add(new MenuItemMvvm("_Duplicate")
{
Command = this.DuplicateCommand,
Icon = new Image
{
Source = new BitmapImage(new Uri("pack://application:,,,/POS.Modules.Core;component/Resources/Images/16X16/Copy.png"))
}
});
menu.Add(new MenuItemMvvm("_Delete")
{
Command = this.DeleteCommand,
Icon = new Image
{
Source = new BitmapImage(new Uri("pack://application:,,,/POS.Modules.Core;component/Resources/Images/16X16/Delete.png"))
}
});
return menu;
}
// Other methods removed for clarity
}