WPF:如何循环遍历 ContextMenu 以重新排列其中的项目或将菜单项作为子项添加到菜单项

WPF: How to loop through ContextMenu to rearrange the items in it or add a menuitem as a subitem to Menu item

我有一个包含以下项目的上下文菜单 我当前的上下文菜单

不过我想要这种格式我的要求

这就是我的进展

 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;

更新代码

IEnumerable oMenuItemList = null;
oMenuItemList = GetContextMenuItems(sMenuItems);

//the function
private List<object> GetContextMenuItems(string sMenuItems)
{
 //returns the list
}

_oContextMenu.ItemsSource = oMenuItemList;

在此之后我试图操纵 _oContextMenu。

以下是您的确切图片示例:

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);
        }
    }
}

这里我使用了特定 headers 文本(“1.1”和“1.2”)的条件,并将项目放在第一个菜单项中,但您可以在特定程序中实现您需要的任何逻辑。

Opened 每次打开上下文菜单时都会触发事件,因此您可以在当前时刻进行所需的任何动态更改。

更新1

以下是涉及 ItemsSource 绑定的示例。优点是您可以只与 MenuItemsCollection 交互,而不必担心 ContextMenu object 本身、它的视觉项目和其他细节。

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);
        }
    }
}

更新2

如果您想每次都直接将新项目列表分配给 ContextMenu 元素:

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;
}

结论

将值设置为 ItemsSource 后,您不能再操作 _oContextMenu,至少它的 Items 属性 - 您会从第一条评论中得到错误。这意味着你不能像我原来的答案那样做,因为你直接分配给 ItemsSource

您尝试将oMenuItemList直接设置为_oContextMenu.ItemsSource(类似于Update2中显示的内容),但之后您无法操作_oContextMenu.Items。你只能操纵你的oMenuItemList(如果你把它保存在全局变量中),但它不会改变实际的菜单内容,因为你的列表不是ObservableCollection

如果您仍然想在代码中做所有事情,试试这个:

ObservableCollection<object> oMenuItemList { get; set; }

...

oMenuItemList = GetContextMenuItems(sMenuItems);

//the function
private ObservableCollection<object> GetContextMenuItems(string sMenuItems)
{
    //returns the ObservableCollection
}

_oContextMenu.ItemsSource = oMenuItemList;

您在 oMenuItemList 中所做的任何更改(但不在 _oContextMenu.Items 中) 将应用到实际的上下文菜单中。

但无论如何,最好的方法仍然是按照 Update1 中的描述进行操作。