获取DataGrid的DataContext在contex菜单中使用它 [英] Getting DataContext of DataGrid to use it in contex menu
问题描述
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屋!