58093

Getting DataContext of DataGrid to use it in contex menu

Question:

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

Answer1:

You could try to use a DataContextProxy, described <a href="http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx" rel="nofollow">here</a>. 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.

<strong>EDIT</strong>

Yes, I tested it myself and indeed it does not work, because the DataContextProxy.Loaded event is never raised ( <a href="https://stackoverflow.com/questions/10446689/wpf-datacontextproxy-in-resources-section" rel="nofollow">it seems we're not the only ones to have hit this problem</a>). 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.

Recommend

  • Doubt regarding a tail optimized code under 'gdb'
  • Pixel perfect collision?
  • Banning by IPv4 and IPv6
  • ScheduledThreadPoolExecutor only “ticking” once
  • Rails 4 order by virtual attribute
  • vue-router and Express
  • Read multiple word strings with java.util.Scanner() [duplicate]
  • Insert null in a database
  • Pass nested C++ vector as built-in style multi-dimensional array
  • Xamarin iOS debugger not hitting breakpoints
  • Full 8 bit adder, illogical output
  • Cryptic error when trying to run POW
  • How do you keep a running instance for Google App Engine
  • WordPress > setting permalink option via script buggy?
  • Change Checkbox value without raising event
  • C#: Import/Export Settings into/from a File
  • d3 v4 drag and drop with TypeScript
  • Ionic 2 storage is not cleaning up on uninstall - Only for signed APK
  • JQuery Internet Explorer and ajaxstop
  • Spark fat jar to run multiple versions on YARN
  • How to do unit test for HttpContext.Current.Server.MapPath
  • Ajax Loaded meta Tags
  • Debugging ASP.NET on a built-in web server suddenly stops
  • Opengl-es onTouchEvents problem or a draw problem? [closed]
  • How to recover from a Spring Social ExpiredAuthorizationException
  • How to model a transition system with SPIN
  • ActionScript 2 vs ActionScript 3 performance
  • Timeout for blocking function call, i.e., how to stop waiting for user input after X seconds?
  • ORA-29908: missing primary invocation for ancillary operator
  • R: gsub and capture
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • Comma separated Values
  • File upload with ng-file-upload throwing error
  • json Serialization in asp
  • Free memory of cv::Mat loaded using FileStorage API
  • Java static initializers and reflection
  • How does Linux kernel interrupt the application?
  • Linking SubReports Without LinkChild/LinkMaster
  • Converting MP3 duration time
  • How to load view controller without button in storyboard?