how to fill context menu from code

1 Answer 63 Views
ContextMenu GridView
Gennady
Top achievements
Rank 2
Iron
Iron
Gennady asked on 01 Feb 2023, 01:37 AM

I"m following example for context menu in grid view:

https://docs.telerik.com/devtools/wpf/controls/radcontextmenu/how-to/use-radcontextmenu-with-radgridview

Sample grid view has context menu on clicking record: Add/Edit/Delete.

Need advice how to create dynamic context menu on-the-fly based on selected row, using parent-child nodes approach like:

- Notify Option1

      - client 1

      - client 2

      - client <...> (items number is variable based on selected row)

- Notify Option2

      - department1

      - department2

      - department<...> (variable)

- Delete

I'm wonder if it is possible to populate menu items in Click_Row() event instead of static init process this.InitializeRowContextMenuItems();

Another approach would be creating separate dialog inside Click_Row() listing all items for each category "Notify Option1", "Notify Option2". But dynamic menu context looks more clean approach.

 

1 Answer, 1 is accepted

Sort by
0
Accepted
Martin Ivanov
Telerik team
answered on 01 Feb 2023, 07:53 AM

Hello Gennady,

To achieve your requirement, you can use the same approach as in the article you linked. The example in the article shows how to pre-initialize the items and then change the ItemsSource of the RadContextMenu control in the Opening event. However, you can move the creation of the items in the Opening event handler, if that would be more dynamic for your scenario. The Opening event is fired on right mouse button down.

For example:

private void GridContextMenu_Opened(object sender, RoutedEventArgs e) 
{ 
	var contextMenu = (RadContextMenu)sender;
	var clickedRow = contextMenu.GetClickedElement<GridViewRow>();
	if (clickedRow != null)
	{
		object dataItem = clickedRow.Item;
		IEnumerable<MyMenuItem> menuItems = GetMenuItemsByRowItem(dataItem);
		contextMenu.ItemsSource = menuItems; 
	}
} 

private IEnumerable<MyMenuItem> GetMenuItemsByRowItem(object dataItem)
{
	// get and return the needed items
}

I hope that helps.

Regards,
Martin Ivanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Gennady
Top achievements
Rank 2
Iron
Iron
commented on 01 Feb 2023, 11:04 PM

Hello, Martin,

following your suggestion created sample solution for dynamic context menu in RadGridView.

Key features: once record selected in grid need to make a trip to VM in order to generate options list. Submenu items added to context menu as ItemsSource (child menu items)

....

            ResetSubMenuItems();
            RadMenuItem menuItem4 = new RadMenuItem();
            menuItem4.Header = "Update";
            menuItem4.IsEnabled = true;
            Player thisPlayer = playersGrid.SelectedItem as Player;
            if (thisPlayer != null && thisPlayer.Number > 1)
            {
                menuItem4.ItemsSource = GetSubMenuItems(thisPlayer);
            }
            else
            {
                menuItem4.Click += MenuUpdate_Click; // should be added once per RadMenuItem
            }
            items.Add(menuItem4);

Later on click row event option index will be extracted in VM:

        private int GetContextMenuSelectionIndex()
        {
            int index = 0;
            foreach (string thisItem in _contextMenuItems)
            {
                if (!thisItem.Equals(_contextMenuSelection))
                    index++;
                else
                    break;
            }

            return index;
        }

Thank you for you propt help!

Best regards,

Gennady

Martin Ivanov
Telerik team
commented on 02 Feb 2023, 11:08 AM

Thank you for sharing your solution. I am glad to see that you managed to get the desired effect. 

One additional tip on the topic: the ItemsSource is intended to be used with a collection of business objects. The associated ItemsControl will generate a container for each element in the ItemsSource. For example, if you have a RadListBox and you populate the ItemsSource with RadListBoxItems, you will end up with bunch of extra and complex objects (RadListBoxItem) in memory with a lot of properties and methods that don't server any purpose. This is why if you use the ItemsSource, it is recommended to use custom class that holds only the information needed by the corresponding item (like the MenuItem class from the help article). If you need to work with the visual elements (like RadListBoxItem), it is better to use the Items collection over ItemsSource.

However, the RadMenu is a bit different, because compared to other ItemsControls it is checking its ItemsSource and is using the RadMenuItems directly if the ItemsSource is populate with items of type RadMenuItem. Anyway, you can note the previous information in mind in order to avoid any unexpected behaviors.

Also, in case you want to minimize your code-behind, you can move the all generation logic in the view model. I've updated your project to show this idea. I hope that is useful.

Gennady
Top achievements
Rank 2
Iron
Iron
commented on 02 Feb 2023, 08:44 PM

This is a great lesson, Martin.

Moving dynamic creation context menu process from view to view model is exactly what i'm looking for.

Thanks a lot for you sample!

Best regards,

Gennady

Tags
ContextMenu GridView
Asked by
Gennady
Top achievements
Rank 2
Iron
Iron
Answers by
Martin Ivanov
Telerik team
Share this question
or