Reputation: 13
I have a ContextMenu with the following items
My current Contextmenu
However I want it in this format My requirement
This is how far I have got
foreach (var menuItem in oMenuItemList)
{
var cContextMenuItem = menuItem as MenuItem;
if (cContextMenuItem != null)
{
_oContextMenu.Items.Add(menuItem);
if (cContextMenuItem.Header.ToString() == "1.1")
{
MenuItem newMenuItem2 = new MenuItem();
MenuItem newExistMenuItem = (MenuItem)this._oContextMenu.Items[0];
newExistMenuItem.Items.Add(newMenuItem2);
_oContextMenu.Items.Add(newExistMenuItem);
}
}
}
_oContextMenu.ItemsSource = oMenuItemList;
Updated code
IEnumerable oMenuItemList = null;
oMenuItemList = GetContextMenuItems(sMenuItems);
//the function
private List<object> GetContextMenuItems(string sMenuItems)
{
//returns the list
}
_oContextMenu.ItemsSource = oMenuItemList;
After this Im trying to manipulate the _oContextMenu.
Upvotes: 1
Views: 1921
Reputation: 1424
Here is example for your exact images:
Xaml:
<ContextMenu Opened="ContextMenu_OnOpened">
<MenuItem Header="1.0" />
<MenuItem Header="1.1" />
<MenuItem Header="1.2" />
<MenuItem Header="2.0" />
<MenuItem Header="3.0" />
</ContextMenu>
Code-behind:
private void ContextMenu_OnOpened(object sender, RoutedEventArgs e)
{
var contextMenu = (ContextMenu)sender;
var firstItem = (MenuItem)contextMenu.Items[0];
// Must create new array of existing menu items
// to be able to edit existing context menu during loop enumeration.
var allItems = contextMenu.Items.Cast<MenuItem>().ToArray();
foreach (var item in allItems)
{
if (item.Header.ToString() == "1.1" || item.Header.ToString() == "1.2")
{
// Add menu item with the same header into another item as sub-item
firstItem.Items.Add(new MenuItem { Header = item.Header });
// Remove item from root level.
contextMenu.Items.Remove(item);
}
}
}
Here I used conditions for specific headers text ("1.1" and "1.2") and put items inside first menu item, but you can implement any logic you need in your particular program.
Opened
event triggers every time context menu opened, so you can make any dynamic changes that required in current moment of time.
Below is example when ItemsSource
binding involved. Advantage is that you can interact just with MenuItemsCollection
and don't worry about ContextMenu
object itself, its visual items and other details.
Xaml:
<TextBox>
<TextBox.ContextMenu>
<ContextMenu Opened="ContextMenu_OnOpened" ItemsSource="{Binding MenuItemsCollection}" />
</TextBox.ContextMenu>
</TextBox>
Code-behind:
public ObservableCollection<MenuItem> MenuItemsCollection { get; set; } = new ObservableCollection<MenuItem>
{
new MenuItem { Header = "1.0" },
new MenuItem { Header = "1.1" },
new MenuItem { Header = "1.2" },
new MenuItem { Header = "2.0" },
new MenuItem { Header = "3.0" },
};
private void ContextMenu_OnOpened(object sender, RoutedEventArgs e)
{
var firstItem = this.MenuItemsCollection[0];
var allItems = this.MenuItemsCollection.ToArray();
foreach (var item in allItems)
{
if (item.Header.ToString() == "1.1" || item.Header.ToString() == "1.2")
{
firstItem.Items.Add(item);
this.MenuItemsCollection.Remove(item);
}
}
}
If you want assign new items list every time directly to ContextMenu
element:
private void ContextMenu_OnOpened(object sender, RoutedEventArgs e)
{
// var actualItems = GetListOfItemsAnyWayYouNeed();
var actualItems = new List<MenuItem>
{
new MenuItem {
Header = "1.0",
Items =
{
new MenuItem { Header = "1.1" },
new MenuItem { Header = "1.2" } }
},
new MenuItem { Header = "2.0" },
new MenuItem { Header = "3.0" },
};
_oContextMenu.ItemsSource = actualItems;
}
After setting value to ItemsSource
, you can not more manipulate the _oContextMenu
, at least its Items
property - you will get error from your first comment. That means you can't do things like in my original answer, because you assign directly to ItemsSource
.
You try to set oMenuItemList
directly to _oContextMenu.ItemsSource
(similar to things shown in Update2), but after that you can't manipulate _oContextMenu.Items
. You can only manipulate your oMenuItemList
(if you save it in global variable), but it will not change actual menu content because your list is not ObservableCollection
.
If you still want to do all things in code, try this:
ObservableCollection<object> oMenuItemList { get; set; }
...
oMenuItemList = GetContextMenuItems(sMenuItems);
//the function
private ObservableCollection<object> GetContextMenuItems(string sMenuItems)
{
//returns the ObservableCollection
}
_oContextMenu.ItemsSource = oMenuItemList;
And any changes you will make in oMenuItemList
(but not in _oContextMenu.Items
) will applied in actual context menu.
But anyway the best approach is still to do like described in Update1.
Upvotes: 2