ここで説明するDataContextProxyの使用を試みることができます。Silverlight 4はWPFのような「RelativeSource」、「AncestorType」をサポートしていないため、DataContextProxyはSilverlight4でネストされたコントロールのDataBindingを簡素化するために使用されます。あなたの場合、コンテキストメニューはビジュアルツリーの一部ではないため、祖先にもアクセスできません。おそらくそれが役立つかもしれません。
編集
はい、私はそれを自分でテストしましたが、DataContextProxy.Loadedイベントが発生することはないため、実際には機能しません(この問題が発生したのは私たちだけではないようです)。それでも、同様のアプローチを使用できます。次の動作を見てください。
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"
);
}
}
コントロールに設定すると、コントロールのDataContextがコントロールのリソースディクショナリで使用できるようになります。それをテストするために、次の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());
}
}
そして次のウィンドウ:
<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>
ビヘイビアーをDataGridにアタッチします。次に、ビヘイビアーはDataGrid.DataContextをそれ自体のDataSourceプロパティにバインドします。次に、DataGridのResourceDictionaryに自分自身を追加します。ContextMenuを定義するときに、静的リソースとして取得できます。