Reputation: 12910
I am cooking up DataGridTemplateColumns programmatically via
DataTemplate dtStringTemplate = (DataTemplate)XamlReader.Load(sr, pc);
dataGridTemplateColumn.CellTemplate = dtStringTemplate;
I tried adding the ContextMenu to the DataGrid, but any editable cells used their own context menu.
So far, this post has gotten me as far as getting the TextBox context menu to appear as expected: How to add a ContextMenu in the WPF DataGridColumn in MVVM?
Using the post mentioned above as a guide, I have created the Style and the ContextMenu in App.xaml; when I right-click on the Cell in the DataGrid, my context menu appears. However, I can't get the associated command to fire, and I suspect the binding is not right. Here's the xaml in App.xaml:
<ContextMenu x:Key="DataGridContextMenu">
<MenuItem Header="MenuItem One" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CmdMenuItemOne}" />
<MenuItem Header="MenuItem Two" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CmdMenuItemOne}" />
</ContextMenu>
The DataContext for the DataGrid is MyViewModel; MyViewModel has a public DelegateCommand named CmdMenuItemOne.
Unfortunately, CmdMenuItemOne is never called.
What am I misunderstanding in the binding? Thanks ...
Upvotes: 0
Views: 470
Reputation: 9827
Use very simple approach given below.
<Window.Resources>
<FrameworkElement x:Key="DCKey" />
</Window.Resources>
public MainWindow()
{
InitializeComponent();
this.DataContext = vm;
((FrameworkElement)this.Resources["DCKey"]).DataContext = vm;
}
<MenuItem Header="DoSomething" Command="{Binding DataContext.Cmd, Source={StaticResource DCKey}}"/>
Upvotes: 1
Reputation: 2782
since the fact that a ContextMenu isn't a part of a DataGrid's visual tree, we cannot access property defined in the DataGrid's DataContext. But we can do the next workaround to do that.
style code (should be in App.xaml)
<Style TargetType="DataGridCell">
<Setter Property="dataGridCreateColumnAndBindIteFromCodeBehind:DataGridAttached.SetDataGridDataContextToTag" Value="True"></Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="MenuItem One"
Command="{Binding CmdMenuItemOne}" />
<MenuItem Header="MenuItem Two"
Command="{Binding CmdMenuItemTwo}" />
</ContextMenu>
</Setter.Value>
</Setter></Style>
attached property code
public class DataGridAttached
{
public static readonly DependencyProperty SetDataGridDataContextToTagProperty = DependencyProperty.RegisterAttached(
"SetDataGridDataContextToTag", typeof (bool), typeof (DataGridAttached), new PropertyMetadata(default(bool), SetParentDataContextToTagPropertyChangedCallback));
public static void SetSetDataGridDataContextToTag(DependencyObject element, bool value)
{
element.SetValue(SetDataGridDataContextToTagProperty, value);
}
public static bool GetSetDataGridDataContextToTag(DependencyObject element)
{
return (bool) element.GetValue(SetDataGridDataContextToTagProperty);
}
private static void SetParentDataContextToTagPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
PerformDataContextToTagAssignment(dependencyObject as FrameworkElement, (bool)args.NewValue);
}
private static void PerformDataContextToTagAssignment(FrameworkElement sender, bool isAttaching)
{
var control = sender;
if (control == null) return;
if (isAttaching == false)
{
control.Tag = null;
}
else
{
var dataGrid = control.FindParent<DataGrid>();
if (dataGrid == null) return;
control.Tag = dataGrid.DataContext;
}
}
}
helper code
public static class VisualTreeHelperExtensions
{
public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
{
while (true)
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
child = parentObject;
}
}
}
Regards.
Upvotes: 0