获取DataGrid的DataContext在contex菜单中使用它 [英] Getting DataContext of DataGrid to use it in contex menu

查看:116
本文介绍了获取DataGrid的DataContext在contex菜单中使用它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,在下列情况下,如何将datagrid datacontext绑定到上下文菜单数据文本:

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

< DataGrid.Resources>
< ContextMenu x:Key =LocalViewerMenuDataContext ={Path to DataGrid.DataContext}>
< MenuItem Header =OpenCommand ={Binding OpenCommand}/>
< / ContextMenu>
< /DataGrid.Resources>

< DataGrid.RowStyle>
< Style TargetType ={x:Type DataGridRow}>
< Setter属性=ContextMenuValue ={StaticResource LocalViewerMenu}/>
< / Style>
< /DataGrid.RowStyle>

< / DataGrid>

我无法直接在DataGrid上设置上下文菜单。它应该是行上下文菜单。



提前感谢

解决方案

您可以尝试使用DataContextProxy,描述 here 。 DataContextProxy在Silverlight 4中用于简化嵌套控件中的DataBinding,因为Silverlight 4不支持RelativeSource,AncestorType,如WPF。在您的情况下,您无法访问祖先,因为上下文菜单不是视觉树的一部分,因此也许可以帮助您。



EDIT



是的,我自己测试了,确实没有工作,因为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();

//将目标数据文本绑定到代理,
//所以每当更改代理将被更新
var binding = new Binding();
binding.Source = this.AssociatedObject;
binding.Path = new PropertyPath(DataContext);
binding.Mode = BindingMode.OneWay;
BindingOperations.SetBinding(this,DataContextProxyBehavior.DataSourceProperty,binding);

//将代理添加到目标
//的资源集合中,因此它将可用于嵌套控件
this.AssociatedObject.Resources.Add(
DataContextProxy,
this
);
}
protected override void OnDetaching()
{
base.OnDetaching();

//从资源中删除代理
this.AssociatedObject.Resources.Remove(
DataContextProxy
);
}
}

一旦你将它设置在控件上,它将会控件的DataContext可以在控件的资源字典中使用。要测试它,我创建了以下ViewModel:

  public class ViewModel:INotifyPropertyChanged 
{
#region INotifyPropertyChanged值

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
if(this.PropertyChanged!= null)
{
this.PropertyChanged(this,new PropertyChangedEventArgs (propertyName));
}
}
#endregion

public ActionCommand Command {get;组; }

public List< string>元素{get;组; }

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 / interactiveivity
xmlns:local =clr-namespace:WpfApplication1
Title =MainWindow
Width =525
Height =350>
< Window.DataContext>
< local:ViewModel />
< /Window.DataContext>
< Grid Name =LayoutRoot>
< DataGrid AutoGenerateColumns =FalseItemsSource ={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时将其作为静态资源。


Hi I have a question about how can I bind datagrid datacontext to context menu datacontext in the following situation:

         <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>

P.S. I can't set context menu to DataGrid directly. It should be as Row context menu.

Thanks in advance

解决方案

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.

这篇关于获取DataGrid的DataContext在contex菜单中使用它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆