您可以尝试使用此处描述的 DataContextProxy 。在 Silverlight 4 中使用 DataContextProxy 来简化嵌套控件中的 DataBinding,因为 Silverlight 4 不像 WPF 那样支持“RelativeSource”、“AncestorType”。在您的情况下,您也无权访问祖先,因为上下文菜单不是可视树的一部分,所以也许它可以帮助您。
编辑
是的,我自己测试过它确实不起作用,因为 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 时将其作为静态资源获取。