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

标签 c# wpf contextmenu

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

但是我想要这种格式我的要求
enter image description here

这是我得到的结果

 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>

代码隐藏:

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

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

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

更新1

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

Xaml:

<TextBox>
    <TextBox.ContextMenu>
        <ContextMenu Opened="ContextMenu_OnOpened" ItemsSource="{Binding MenuItemsCollection}" />
    </TextBox.ContextMenu>
</TextBox>

代码隐藏:

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 中的描述进行操作。

关于c# - WPF:如何循环遍历 ContextMenu 以重新排列其中的项目或将菜单项作为子项添加到菜单项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37452800/

相关文章:

c# - 我如何以通用形式实现 NULL 对象设计模式?

WPF DropShadowEffect 导致模糊

c# - 如何在 WPF 组合框中找到插入符位置?

wpf - 使用 MVVM 的上下文菜单项命令绑定(bind) WPF

javascript - 如何获取表中调用行的第一列值?

c# - 当我点击其他地方时,我的 WPF ContextMenu 没有消失

c# - 仅使用日期时间格式比较日期和显示时间

c# - 如何处理 OO 应用程序中的横切关注点?使用单例?依赖注入(inject)?什么?

c# - 在 C# 中,为什么在这种情况下使用字段与自动实现的属性会导致不同的行为?

.net - 在WPF中使用自定义字体