0

嗨,我有一个关于如何在以下情况下将 datagrid datacontext 绑定到上下文菜单 datacontext 的问题:

         <DataGrid DataContext="{Binding someDataContext}" ItemsSource="{Binding items}">

            <DataGrid.Resources>
                    <ContextMenu  x:Key="LocalViewerMenu" DataContext="{path to DataGrid.DataContext}">
                                <MenuItem Header="Open" Command="{Binding OpenCommand}"/>
                    </ContextMenu>
            </DataGrid.Resources>

            <DataGrid.RowStyle>
                    <Style TargetType="{x:Type DataGridRow}">
                          <Setter Property="ContextMenu" Value="{StaticResource LocalViewerMenu}"/>
                    </Style>
            </DataGrid.RowStyle>

          </DataGrid>

PS 我不能直接将上下文菜单设置为 DataGrid。它应该作为 Row 上下文菜单。

提前致谢

4

1 回答 1

2

您可以尝试使用此处描述的 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 时将其作为静态资源获取。

于 2012-11-19T16:31:34.620 回答