I have a Window with a viewmodel as the DataContext. My window contains an ItemsControl with its ItemsSource bound to a viewmodel object collection.
My ItemsControl uses a Canvas for the ItemsPanelTemplate. The DataTemplate includes an Ellipse with a ContextMenu associated with it; that ContextMenu has a single MenuItem.
My Window viewmodel contains an ICommand which takes an object parameter (the current ItemsSource item).
I am attempting to right-click on one of the ellipses within my ItemsControl and bring up the ContextMenu, then click on the MenuItem to execute the ICommand and pass the current ItemsSource item as a parameter.
For some reason, I am unable to access the Window's DataContext from within the ContextMenu. I've tried to research this issue, but none of the proposed solutions seem to work for me.
I've tried gaining access to the Window datacontext by using the Window's elementname, and by finding ancestor type, no luck however.
public class VM_MainWindow : ViewModelBase
{
public DelegateCommand<EllipseObject> TestClick { get; }
// constructor
public VM_MainWindow()
{
// initialization
EllipseCollection = DynamicData.Ellipses;
ScreenResolutionWidth = ClientConfig.Info.ScreenResolutionWidth - 8;
ScreenResolutionHeight = ClientConfig.Info.ScreenResolutionHeight - 120;
// commands
TestClick = new DelegateCommand<EllipseObject>(OnTestClickCommand);
}
#region "Properties"
private ObservableCollection<EllipseObject> _ellipseCollection;
public ObservableCollection<EllipseObject> EllipseCollection
{
get => _ellipseCollection;
set
{
_ellipseCollection = value;
OnPropertyChanged("EllipseCollection");
}
}
private int _screenResolutionWidth;
public int ScreenResolutionWidth
{
get => _screenResolutionWidth;
set
{
_screenResolutionWidth = value;
OnPropertyChanged("ScreenResolutionWidth");
}
}
private int _screenResolutionHeight;
public int ScreenResolutionHeight
{
get => _screenResolutionHeight;
set
{
_screenResolutionHeight = value;
OnPropertyChanged("ScreenResolutionHeight");
}
}
#endregion
private void OnTestClickCommand(EllipseObject eObj)
{
MessageBox.Show("Ellipse Name: " + eObj.DisplayName, "Test", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
public class DelegateCommand<T> : System.Windows.Input.ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public DelegateCommand(Action<T> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
return true;
return _canExecute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public void Execute(object parameter)
{
_execute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
and here's the MainWindow.xaml, note that my window is named x:Name="mainWindow":
<Window.DataContext>
<viewModels:VM_MainWindow/>
</Window.DataContext>
<Grid Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="27px"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="30px"/>
</Grid.RowDefinitions>
<Grid x:Name="icContainerGrid" Grid.Row="1" Background="{Binding TrackMapBackground}">
<Grid>
<!-- ELLIPSES -->
<ItemsControl ItemsSource="{Binding EllipseCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" Width="{Binding ScreenResolutionWidth}" Height="{Binding ScreenResolutionHeight}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X1}"/>
<Setter Property="Canvas.Top" Value="{Binding Y1}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="24" Height="24" Fill="Red">
<Ellipse.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu item 1" Command="{Binding ElementName=mainWindow, Path=DataContext.TestClick}" CommandParameter="{Binding}"/>
</ContextMenu>
</Ellipse.ContextMenu>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
</Grid>
I expected my command to fire upon clicking the MenuItem, however it does not.
I receive the following binding error upon running the application:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=mainWindow'. BindingExpression:Path=DataContext.TestClick; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')