Silverlight: right-click ContextMenu for a DataGrid

It required some digging to get it right, all the solutions I’ve found by googling were insufficient.
Here are the problems I had to solve:
– Adding the ContextMenu on the DataGrid made it work on the headers as well, I wanted it only on the ‘body’, excluding headers.
– Adding the ContextMenu of each row using the LoadingRow event involved making lots new instances of the menu, and it raised some thinking about performance with large data and virtualization.
– I wanted it to be simple to use, easy to add commands etc. simply as we adding a ContextMenu elsewhere.
– Should be used in XAML, not code.

Parts of my code is borrowed from Craig Wardman blog, thanks.

Here is the code, and down below is how you use it:

public class DataGridContextMenuBehavior : Behavior<DataGrid>
    protected override void OnAttached()

        if (ContextMenu != null) AssociatedObject.LayoutUpdated += AssociatedObjectOnLayoutUpdated;
            new MouseButtonEventHandler(OnMouseRightButtonDown), true);

    private void AssociatedObjectOnLayoutUpdated(object sender, EventArgs eventArgs)
        if(ContextMenu == null) return;
        var rowsPresenter = FindChildControlByType<DataGridRowsPresenter>(AssociatedObject);

        if (rowsPresenter != null)
            ContextMenuService.SetContextMenu(rowsPresenter, ContextMenu);
            AssociatedObject.LayoutUpdated -= AssociatedObjectOnLayoutUpdated;

    protected override void OnDetaching()

        AssociatedObject.MouseRightButtonDown -= OnMouseRightButtonDown;

    private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        var elementsUnderMouse = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null),

        var row = elementsUnderMouse.OfType<DataGridRow>().FirstOrDefault();

        if (row != null)
            AssociatedObject.SelectedItem = row.DataContext;

    #region ContextMenu (DependencyProperty)

    public ContextMenu ContextMenu
        get { return (ContextMenu)GetValue(ContextMenuProperty); }
        set { SetValue(ContextMenuProperty, value); }
    public static readonly DependencyProperty ContextMenuProperty =
        DependencyProperty.Register("ContextMenu", typeof(ContextMenu), typeof(DataGridContextMenuBehavior),
            new PropertyMetadata(null)


    #region find child control by type

    private static T FindChildControlByType<T>(DependencyObject container) where T : DependencyObject
        return FindChildControlByType<T>(container, null);

    private static T FindChildControlByType<T>(DependencyObject container, string name) where T : DependencyObject
        T foundControl = null;

        //for each child object in the container
        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(container); i++)
            //is the object of the type we are looking for?
            if (VisualTreeHelper.GetChild(container, i) is T &&
                (VisualTreeHelper.GetChild(container, i).GetValue(FrameworkElement.NameProperty).Equals(name) ||
                    name == null))
                foundControl = (T) VisualTreeHelper.GetChild(container, i);
            //if not, does it have children?
            if (VisualTreeHelper.GetChildrenCount(VisualTreeHelper.GetChild(container, i)) > 0)
                //recursively look at its children
                foundControl = FindChildControlByType<T>(VisualTreeHelper.GetChild(container, i), name);
                if (foundControl != null)

        return foundControl;


example of use:

<sdk:DataGrid Name="DataGrid1"
                ItemsSource="{Binding SourceCollection}">
                    <toolkit:MenuItem Header="Cut"
                                        Click="MenuItem_OnCut" />
                    <toolkit:MenuItem Header="Copy"
                                        Command="{Binding OnCopyCommand}" />

WPF: DataGrid with integrated field (column) chooser

following a discussion in the comments of this post
this is the WPF version of a DataGrid control with integrated columns chooser that opens when right-clicking one of the headers.
(see Silverlight demo)
full source code over here

this is how it look like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace WPF_DataGridWithColumnChooser.Controls
    public class DataGridExtended : DataGrid
        public DataGridExtended()
            : base()
            theContextMenu = new ContextMenu();
            this.Columns.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Columns_CollectionChanged);

        private ContextMenu theContextMenu; //context menu for the field chooser.
        private string AllColumnsHeaders { get; set; }
        private bool oneTime = true;

        protected override Size ArrangeOverride(Size finalSize)
            if (oneTime)// do this only once.
                oneTime = false;
                var headersPresenter = FindChild(this);
                // attach the context menu.
                ContextMenuService.SetContextMenu(headersPresenter, theContextMenu);

                // update VisibleColumns as necessary.
                if (String.IsNullOrEmpty(VisibleColumns))
                    VisibleColumns = AllColumnsHeaders;
                    string s = VisibleColumns;
                    VisibleColumns = null;
                    VisibleColumns = s;
            return base.ArrangeOverride(finalSize);

        private void MenuItem_Click(object sender, RoutedEventArgs e)
            MenuItem mi = sender as MenuItem;
            Image icon = (Image)mi.Icon;
            List splited = VisibleColumns.Split(';').ToList();
            string colName = mi.Header.ToString();

            // remove empty items.
            for (int i = 0; i  1)

            // update the VisibleColumns.
            string build = "";
            foreach (string name in splited)
                build = string.Format("{0};{1}", name, build);
            VisibleColumns = build;

        private void Columns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

            DataGridColumn col = e.NewItems[0] as DataGridColumn;

            // keep a list of all clomuns headers for later use.
            AllColumnsHeaders = String.Format("{0};{1}", col.Header.ToString(), AllColumnsHeaders);

            // make a new menu item and add it to the context menu.
            MenuItem menuItem = new MenuItem();
            Image img;
            menuItem.Click += new RoutedEventHandler(MenuItem_Click);
            menuItem.Header = col.Header.ToString();
            img = new Image();
            img.Source = Application.Current.Resources["Vmark"] as ImageSource;
            menuItem.Icon = img;


        #region VisibleColumns (DependencyProperty)

        /// <summary>
        /// Gets or sets a value indicating the names of columns (as they appear in the column header) to be visible, seperated by a semicolon.
        /// columns that whose name is not here will be hidden.
        /// </summary>
        public string VisibleColumns
            get { return (string)GetValue(VisibleColumnsProperty); }
            set { SetValue(VisibleColumnsProperty, value); }

        public static readonly DependencyProperty VisibleColumnsProperty =
                new PropertyMetadata("", new PropertyChangedCallback(OnVisibleColumnsChanged))

        private static void OnVisibleColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            DataGridExtended dg = (DataGridExtended)d;


        private void VisibleColumnsChanged(DependencyPropertyChangedEventArgs e)
            if (e.NewValue != null)
                string[] showTheseColumns = e.NewValue.ToString().Split(';');
                string colName;

                // update the columns visibility.
                foreach (DataGridColumn col in this.Columns)
                    colName = col.Header.ToString();

                    if (showTheseColumns.Contains(colName))
                        col.Visibility = Visibility.Visible;
                        col.Visibility = Visibility.Collapsed;

                // update the context menu items.
                if (theContextMenu != null)
                    foreach (MenuItem menuItem in theContextMenu.Items)
                        colName = menuItem.Header.ToString();
                        if (showTheseColumns.Contains(colName))
                            ((Image)menuItem.Icon).Visibility = Visibility.Visible;
                            ((Image)menuItem.Icon).Visibility = Visibility.Collapsed;


        public static T FindChild(DependencyObject depObj) where T : DependencyObject
            // Confirm obj is valid.
            if (depObj == null) return null;

            // success case
            if (depObj is T)
                return depObj as T;

            for (int i = 0; i &lt; VisualTreeHelper.GetChildrenCount(depObj); i++)
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

                T obj = FindChild(child);

                if (obj != null)
                    return obj;

            return null;


Silverlight: DataGrid with integrated field (column) chooser

Not much to say here, it speaks for itself.

Right click on a column header to open the field (columns) chooser and show/hide columns.

The VisibleColumns property is always up-to-date and can be binded TwoWay, in my case I am saving it to the user preferences for consistency.

Take a look at the code to see how it’s done.

Notice: ContextMenu causes memory leak! as long as you don’t need to remove the DataGrid you are OK.

Demo is Here
Source is here

the WPF version is over here