You could try to use a DataContextProxy, described here. The DataContextProxy is used in Silverlight 4 to simplify DataBinding in nested controls, because Silverlight 4 does not support "RelativeSource", "AncestorType", like WPF. In your case, you don't have access to the ancestor neither, as the context menu is not part of the visual tree, so maybe it can help you.
EDIT
Yes, I tested it myself and indeed it does not work, because the DataContextProxy.Loaded event is never raised ( it seems we're not the only ones to have hit this problem). Nevertheless, we can use a similar approach. Take a look on the following behavior:
public class DataContextProxyBehavior : Behavior<FrameworkElement>
{
public Object DataSource
{
get { return (Object)GetValue(DataSourceProperty); }
set { SetValue(DataSourceProperty, value); }
}
public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register("DataSource", typeof(Object), typeof(DataContextProxy), null);
protected override void OnAttached()
{
base.OnAttached();
// Binds the target datacontext to the proxy,
// so whenever it changes the proxy will be updated
var binding = new Binding();
binding.Source = this.AssociatedObject;
binding.Path = new PropertyPath("DataContext");
binding.Mode = BindingMode.OneWay;
BindingOperations.SetBinding(this, DataContextProxyBehavior.DataSourceProperty, binding);
// Add the proxy to the resource collection of the target
// so it will be available to nested controls
this.AssociatedObject.Resources.Add(
"DataContextProxy",
this
);
}
protected override void OnDetaching()
{
base.OnDetaching();
// Removes the proxy from the Resources
this.AssociatedObject.Resources.Remove(
"DataContextProxy"
);
}
}
Once you set it on a control, it will make the control's DataContext available in the control's resource dictionary. To test it, I created the following ViewModel:
public class ViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged values
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public ActionCommand Command { get; set; }
public List<string> Elements { get; set; }
public ViewModel()
{
this.Elements = new List<string>(){
"Element1",
"Element2"
};
this.Command = new ActionCommand()
{
ExecuteDelegate = this.Execute
};
}
public void Execute(object o)
{
MessageBox.Show(o.ToString());
}
}
And the following Window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow"
Width="525"
Height="350">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid Name="LayoutRoot">
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Elements}">
<i:Interaction.Behaviors>
<local:DataContextProxyBehavior />
</i:Interaction.Behaviors>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Command="{Binding DataSource.Command,
Source={StaticResource DataContextProxy}}"
CommandParameter="{Binding}"
Header="Open" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}" Header="MyHeader" />
</DataGrid.Columns>
</DataGrid>
</Grid>
We attach the behavior to the DataGrid. The behavior will then bind the DataGrid.DataContext to it's own DataSource property. Next, it will add itself to the DataGrid's ResourceDictionary. We can then get it as a staticresource when defining the ContextMenu.