Popup Menus

  • 13 minutes to read

This topic shows how to customize a Data Grid's built-in popup menus, override the default menu item actions, and use events to create custom popup menus.

NOTE

This topic does not cover in-place editors' menu items.

In this topic:

Built-In Context Menus

The Data Grid's Grid Views and Banded Grid Views have five built-in context menus.

The properties the Views provide can affect the availability of certain items in these menus. For instance, when you disable the GridOptionsCustomization.AllowSort option, the "Sort Ascending" and "Sort Descending" items are automatically deactivated in the Column Header Menu.

Not all menu items can be hidden using the View's properties. To control the visibility of any menu item, use the GridView.PopupMenuShowing event as described below.

Customize, Hide and Disable Default Menu Items

To customize menu items (for example, change their captions and visibility), handle the GridView.PopupMenuShowing event. This event fires each time the menu is invoked.

The event's e.Menu parameter allows you to get the displayed menu. You can iterate through the e.Menu.Items collection or call the e.Menu.Find and e.Menu.FindAll methods to access individual menu items. To hide or remove certain menu items, use the e.Menu.Hide and e.Menu.Remove methods. These methods accept menu item identifiers as parameters. Refer to PopupMenuShowingEventArgs.Menu for information about menu item identification.

Example

The following code customizes the existing commands in the Data Grid's Column Header Menu by handling the GridView.PopupMenuShowing event:

  • Captions of the "Sort Ascending" and "Sort Descending" commands are replaced with custom strings;

  • A few commands are hidden;

  • Two "Best Fit" commands are disabled.

PopupMenuShowing-RenameAndHide

using DevExpress.Utils.Menu;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Localization;
using DevExpress.XtraGrid.Views.Grid;

private void gridView1_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e) {
    if(e.MenuType == GridMenuType.Column) {
        string sortAsc = "A to Z";
        string sortDesc = "Z to A";
        if (e.HitInfo.Column.ColumnType == typeof(DateTime)) {
            sortAsc = "Old to New";
            sortDesc = "New to Old";
        }
        DXMenuItem itemAsc = e.Menu.Find(GridStringId.MenuColumnSortAscending); // "Sort Ascending"
        if (itemAsc != null)
            itemAsc.Caption = sortAsc;

        DXMenuItem itemDesc = e.Menu.Find(GridStringId.MenuColumnSortDescending); // "Sort Descending"
        if (itemDesc != null)
            itemDesc.Caption = sortDesc;

        e.Menu.Hide(GridStringId.MenuFooterHide); //"Hide Footer"
        e.Menu.Hide(GridStringId.MenuColumnFilterEditor); // "Filter Editor..."
        e.Menu.Hide(GridStringId.MenuColumnFindFilterShow); // "Show Find Panel"
        e.Menu.Hide(GridStringId.MenuColumnFindFilterHide); // "Hide Find Panel"
        e.Menu.Hide(GridStringId.MenuColumnAutoFilterRowHide); // "Hide Auto Filter Row"
        e.Menu.Hide(GridStringId.MenuColumnAutoFilterRowShow); // "Show Auto Filter Row"

        DXMenuItem itemBestFit = e.Menu.Find(GridStringId.MenuColumnBestFit); // "Best Fit"
        if (itemBestFit != null)
            itemBestFit.Enabled = false;

        DXMenuItem itemBestFitAll = e.Menu.Find(GridStringId.MenuColumnBestFitAllColumns); // "Best Fit All Columns"
        if (itemBestFitAll != null)
            itemBestFitAll.Enabled = false;
    }
}

Add Custom Items to Built-In Menus

Handle the GridView.PopupMenuShowing event and add custom items to the event's e.Menu.Items parameter. You can use the following objects as custom items:

Example

The following example shows how to use the GridView.PopupMenuShowing event to create a custom menu in the Data Grid control. The created menu is displayed when you right-click within a data row or group row. It contains a 'Rows' submenu with a single "Delete this row" regular button, and a 'Cell Merging' check button.

DXMenuItem_Ex

A click on the 'Delete this row' button invokes the ColumnView.DeleteRow method. The 'Cell Merging' check button toggles the GridOptionsView.AllowCellMerge option.

using DevExpress.XtraGrid.Views.Grid;
using DevExpress.Utils.Menu;
using DevExpress.XtraEditors;

private void gridView1_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e) {
    GridView view = sender as GridView;
    if (e.MenuType == DevExpress.XtraGrid.Views.Grid.GridMenuType.Row) {
        int rowHandle = e.HitInfo.RowHandle;
        // Delete existing menu items, if any.
        e.Menu.Items.Clear();
        // Add the Rows submenu with the 'Delete Row' command
        e.Menu.Items.Add(CreateSubMenuRows(view, rowHandle));
        // Add the 'Cell Merging' check menu item.
        DXMenuItem item = CreateMenuItemCellMerging(view, rowHandle);
        item.BeginGroup = true;
        e.Menu.Items.Add(item);
    }
}

DXMenuItem CreateSubMenuRows(GridView view, int rowHandle) {
    DXSubMenuItem subMenu = new DXSubMenuItem("Rows");
    string deleteRowsCommandCaption;
    if (view.IsGroupRow(rowHandle))
        deleteRowsCommandCaption = "&Delete rows in this group";
    else
        deleteRowsCommandCaption = "&Delete this row";
    DXMenuItem menuItemDeleteRow = new DXMenuItem(deleteRowsCommandCaption, new EventHandler(OnDeleteRowClick), imageCollection1.Images[0]);
    menuItemDeleteRow.Tag = new RowInfo(view, rowHandle);
    menuItemDeleteRow.Enabled = view.IsDataRow(rowHandle) || view.IsGroupRow(rowHandle);
    subMenu.Items.Add(menuItemDeleteRow);
    return subMenu;
}

DXMenuCheckItem CreateMenuItemCellMerging(GridView view, int rowHandle) {
    DXMenuCheckItem checkItem = new DXMenuCheckItem("Cell &Merging",
      view.OptionsView.AllowCellMerge, null, new EventHandler(OnCellMergingClick));
    checkItem.Tag = new RowInfo(view, rowHandle);
    checkItem.ImageOptions.Image = imageCollection1.Images[1];
    return checkItem;
}

void OnDeleteRowClick(object sender, EventArgs e) {
    DXMenuItem menuItem = sender as DXMenuItem;
    RowInfo ri = menuItem.Tag as RowInfo;
    if (ri != null) {
        string message = menuItem.Caption.Replace("&", "");
        if (XtraMessageBox.Show(message + " ?", "Confirm operation", MessageBoxButtons.YesNo) != DialogResult.Yes)
            return;
        ri.View.DeleteRow(ri.RowHandle);
    }
}

void OnCellMergingClick(object sender, EventArgs e) {
    DXMenuCheckItem item = sender as DXMenuCheckItem;
    RowInfo info = item.Tag as RowInfo;
    info.View.OptionsView.AllowCellMerge = item.Checked;
}

class RowInfo {
    public RowInfo(GridView view, int rowHandle) {
        this.RowHandle = rowHandle;
        this.View = view;
    }
    public GridView View;
    public int RowHandle;
}

Example

The following sample code handles the GridView.PopupMenuShowing event to customize the column header context menu before it is displayed. The code clears default menu items and adds a new command that locks a clicked column's position.

GridView_ShowGridMenu

using DevExpress.XtraGrid.Menu;
using DevExpress.Utils.Menu;
using DevExpress.XtraGrid.Columns; 
using DevExpress.XtraGrid.Views.Grid;
// ...
private void bandedGridView1_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e) {
    if(e.MenuType == GridMenuType.Column) {
        GridViewColumnMenu menu = e.Menu as GridViewColumnMenu;
        menu.Items.Clear();
        if(menu.Column != null) {
            menu.Items.Add(CreateCheckItem("Lock this column", menu.Column, null));
        }
    }
}

// Creates a menu item.
DXMenuCheckItem CreateCheckItem(string caption, GridColumn column, Image image) {
    DXMenuCheckItem item = new DXMenuCheckItem(caption, 
      !column.OptionsColumn.AllowMove, image, new EventHandler(OnCanMoveItemClick));
    item.Tag = new MenuColumnInfo(column);
    return item;
}

// Menu item click handler.
void OnCanMoveItemClick(object sender, EventArgs e) {
    DXMenuCheckItem item = sender as DXMenuCheckItem;
    MenuColumnInfo info = item.Tag as MenuColumnInfo;
    if(info == null) return;
    info.Column.OptionsColumn.AllowMove = !item.Checked;
}

class MenuColumnInfo {
    public MenuColumnInfo(GridColumn column) {
        this.Column = column;               
    }
    public GridColumn Column;
}

Change Menu Items' Default Behavior

A click on a menu item in the built-in context menus raises the GridView.GridMenuItemClick event. After your event handler is complete, the grid performs the menu item's related action by default. You can handle the GridMenuItemClick event to:

  • Perform custom actions
  • Prevent the default action from being invoked after your event handler is complete, by setting the event's Handled parameter to true.

Example

The following example handles the GridView.GridMenuItemClick event to show a warning when you select the "Hide This Column" command from the column header menu. Pressing 'No' in the message box cancels the invoked action.

private void gridView1_GridMenuItemClick(object sender, DevExpress.XtraGrid.Views.Grid.GridMenuItemClickEventArgs e) {
    if(e.MenuType == DevExpress.XtraGrid.Views.Grid.GridMenuType.Column) {
        GridStringId value = e.DXMenuItem.Tag is GridStringId ? (GridStringId)e.DXMenuItem.Tag : 0 ;
        if (value == GridStringId.MenuColumnRemoveColumn) { //"Hide This Column" command
            if(MessageBox.Show("Do you want to hide this column?", "Warning", MessageBoxButtons.YesNo)== DialogResult.No) {
                e.Handled = true; //Cancel further default processing
            }
        }
    }
}

Show a Custom Popup Menu for Any Grid Element

You can create and show a custom context menu within a View's BaseView.MouseDown event handler. When handling this event, identify the clicked element with the BaseView.CalcHitInfo method. This method returns information about a grid element at the specified screen point.

Use the GridViewMenu class to create a custom menu instance for Grid Views and Banded Grid Views. You can add the following menu item objects to the GridViewMenu.Items collection:

Example

This example creates a custom context menu that is displayed on right-clicking the header panel button. This menu has two items: Columns and Runtime Column Customization. The first item is a sub menu that allows you to show/hide grid columns. The second item invokes the Customization Form.

Creating Custom Context Menus

private void gridView1_MouseDown(object sender, MouseEventArgs e) {
    GridView view = sender as GridView;
    if (e.Button == MouseButtons.Right)
        DoShowMenu(view.CalcHitInfo(new Point(e.X, e.Y)));
}

void DoShowMenu(DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitInfo hi) {
    DevExpress.XtraGrid.Menu.GridViewMenu menu = null;
    // Check whether the header panel button has been clicked. 
    if (hi.HitTest == DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitTest.ColumnButton) {
        menu = new GridViewColumnButtonMenu(hi.View);
        menu.Init(hi);
        menu.Show(hi.HitPoint);
    }
}

public class GridViewColumnButtonMenu : GridViewMenu {
    public GridViewColumnButtonMenu(DevExpress.XtraGrid.Views.Grid.GridView view) : base(view) { }

    // This method is automatically called by the menu's public Init method. 
    protected override void CreateItems() {
        Items.Clear();
        DXSubMenuItem submenuColumns = new DXSubMenuItem("Columns");
        Items.Add(submenuColumns);
        Items.Add(CreateMenuItem("Runtime Column Customization", GridMenuImages.Column.Images[3], "Customization", true));
        foreach (GridColumn column in View.Columns) {
            if (column.OptionsColumn.ShowInCustomizationForm && column.GroupIndex<0) {
                submenuColumns.Items.Add(CreateMenuCheckItem(column.GetCaption(), column.Visible, null, column, true));
            }
        }
    }

    protected override void OnMenuItemCheckedChanged(object sender, EventArgs e) {
        DXMenuCheckItem item = sender as DXMenuCheckItem;
        if (item.Tag is GridColumn) {
            GridColumn column = item.Tag as GridColumn;
            column.Visible = item.Checked;
        }
    }

    protected override void OnMenuItemClick(object sender, EventArgs e) {
        DXMenuItem item = sender as DXMenuItem;
        if (item.Tag == null) return;
        if (item.Tag.ToString() == "Customization") View.ShowCustomization();
    }
}

By default, the Data Grid paints its menus according to the system settings, without taking into account the current skin.

To apply a skin to the Data Grid's menus, place a BarManager or RibbonControl component onto the form. This component is automatically bound to the Data Grid's EditorContainer.MenuManager property. The RibbonControl/BarManager now manages the display of the grid's menus, and applies the selected paint scheme (skin) to them.

The following image shows a column header menu painted using different themes.

popupmenus-differentpaintschemes.png

You can use the Project Settings Page or the DefaultLookAndFeel component to customize the default paint scheme for all controls, including the data grid's popup menus.