I'm trying to show a ContextMenu when right clicking a particular type of cell in a DataGridView. If I click the cell to select it before right-clicking to bring up the context menu it works as expected.
If I right-click the cell without clicking to select it first however, my application crashes because of an unhandled exception.
System.ArgumentNullException: 'Value cannot be null. (Parameter 'container')'
I've looked around and I think the answer from WPF Contextmenu itemtemplate commandParameter binding returns null is basically what I need to do but I don't understand how to apply this to my problem.
Edit: Here's the entire call stack
> PresentationFramework.dll!System.Windows.Controls.ItemContainerGenerator.ItemFromContainer(System.Windows.DependencyObject container) Unknown
PresentationFramework.dll!System.Windows.Controls.ItemsControl.ItemInfoFromContainer(System.Windows.DependencyObject container) Unknown
PresentationFramework.dll!System.Windows.Controls.DataGrid.HandleSelectionForCellInput(System.Windows.Controls.DataGridCell cell, bool startDragging, bool allowsExtendSelect, bool allowsMinimalSelect) Unknown
PresentationFramework.dll!System.Windows.Controls.DataGrid.OnContextMenuOpening(System.Windows.Controls.ContextMenuEventArgs e) Unknown
PresentationFramework.dll!System.Windows.FrameworkElement.OnContextMenuOpeningThunk(object sender, System.Windows.Controls.ContextMenuEventArgs e) Unknown
PresentationFramework.dll!System.Windows.Controls.ContextMenuEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) Unknown
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) Unknown
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) Unknown
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) Unknown
PresentationFramework.dll!System.Windows.Controls.PopupControlService.RaiseContextMenuOpeningEvent(System.Windows.IInputElement source, double x, double y, bool userInitiated) Unknown
PresentationFramework.dll!System.Windows.Controls.PopupControlService.ProcessMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) Unknown
PresentationFramework.dll!System.Windows.Controls.PopupControlService.OnPostProcessInput(object sender, System.Windows.Input.ProcessInputEventArgs e) Unknown
PresentationCore.dll!System.Windows.Input.InputManager.RaiseProcessInputEventHandlers(System.Windows.Input.ProcessInputEventHandler postProcessInput, System.Windows.Input.ProcessInputEventArgs processInputEventArgs) Unknown
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() Unknown
PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) Unknown
PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawMouseActions actions, int x, int y, int wheel) Unknown
PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.FilterMessage(System.IntPtr hwnd, MS.Internal.Interop.WindowMessage msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
PresentationCore.dll!System.Windows.Interop.HwndSource.InputFilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Unknown
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() Unknown
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) Unknown
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) Unknown
PresentationFramework.dll!System.Windows.Application.Run() Unknown
Testproject.dll!Testproject.App.Main() Unknown
Edit again; here is the full XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.Resources>
<!-- Default DataTemplate -->
<DataTemplate x:Key="DefaultDataTemplate">
<TextBox Text="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
<!-- DataTemplate for Booleans -->
<DataTemplate x:Key="BooleanDataTemplate">
<CheckBox IsChecked="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
<!-- DataTemplate for Arrays -->
<DataTemplate x:Key="ArrayDataTemplate">
<DataGridCell Content="{Binding Path=Value, Mode=OneWay}" >
<DataGridCell.ContextMenu>
<ContextMenu>
<MenuItem Header="View / Edit..." />
</ContextMenu>
</DataGridCell.ContextMenu>
</DataGridCell>
</DataTemplate>
<local:ValueDataTemplateSelector x:Key="templateSelector"
DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
BooleanDataTemplate="{StaticResource BooleanDataTemplate}"
ArrayDataTemplate="{StaticResource ArrayDataTemplate}" />
</Grid.Resources>
<DataGrid Name="DG2" ItemsSource="{Binding TagListView}" AutoGenerateColumns="False" Grid.Row="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="*" Binding="{Binding Path=Name, Mode=OneWay}" />
<DataGridTemplateColumn Header="Value" Width="2*" CellTemplateSelector="{StaticResource templateSelector}" CellEditingTemplateSelector="{StaticResource templateSelector}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
I solved the problem.
With reference to this XAML:
<!-- DataTemplate for Arrays -->
<DataTemplate x:Key="ArrayDataTemplate">
<DataGridCell Content="{Binding Path=Value, Mode=OneWay}" >
<DataGridCell.ContextMenu>
<ContextMenu>
<MenuItem Header="View / Edit..." />
</ContextMenu>
</DataGridCell.ContextMenu>
</DataGridCell>
</DataTemplate>
Any DataGridTemplateColumn a DataTemplate is applied to already contains DataGridCells in every row.
So when I'm putting a DataGridCell inside the DataTemplate, I'm actually putting a DataGridCell inside the existing DataGridCell. This causes the problems when right clicking the cell. The ContextMenu is actually irrelevant, the problem occurs regardless.
This can be fixed by using another type of Container in the DataTemplate, for example like this:
<!-- DataTemplate for Arrays -->
<DataTemplate x:Key="ArrayDataTemplate">
<TextBox Text="{Binding Path=Value, Mode=OneWay}" >
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="View / Edit..." Click="menuItem_Click" />
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</DataTemplate>