Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将ToolStripMenuItems从不同MEF插件合并到一个MenuStrip中_C#_Winforms_Plugins_Mef - Fatal编程技术网

C# 将ToolStripMenuItems从不同MEF插件合并到一个MenuStrip中

C# 将ToolStripMenuItems从不同MEF插件合并到一个MenuStrip中,c#,winforms,plugins,mef,C#,Winforms,Plugins,Mef,目前,我尝试将不同的ToolStripMenuItems合并为一个MenuStrip。因此,我创建了一个名为IMenu的接口。这包括来自MEF插件的ToolStripMenuItem,应该加载到主窗口Menustrip中。问题是,如果我运行应用程序,我会在MenuStrip中找到两个同名的下拉元素。但是我想要的是,我可以将MEF插件的菜单绑定到应用程序的MenuStrip中,而无需双重输入,例如。 如何为MEF插件创建一个好的菜单结构 示例:我已从主应用程序中获取此条目 文件 |-->新的 |-

目前,我尝试将不同的
ToolStripMenuItems
合并为一个
MenuStrip
。因此,我创建了一个名为
IMenu
的接口。这包括来自MEF插件的
ToolStripMenuItem
,应该加载到主窗口Menustrip中。问题是,如果我运行应用程序,我会在
MenuStrip
中找到两个同名的下拉元素。但是我想要的是,我可以将MEF插件的菜单绑定到应用程序的MenuStrip中,而无需双重输入,例如。 如何为MEF插件创建一个好的菜单结构

示例:我已从主应用程序中获取此条目

文件
|-->新的
|-->保存
|-->导入
|-->出口

然后我创建了一个插件,用于导入/导出特定类型。因此,我必须在菜单中动态添加导入/导出下的条目。但是怎么做呢?你的解决方案怎么样

文件
|-->新的
|-->保存
|-->导入
|----->到Word
|-->导出
|----->从字里行间

这是我的代码: 首先是插件的接口

public interface IMenu
{
  ToolStripMenuItem ToolStripItem { get; }
}
这是一个菜单项的插件示例

帮助
|-->更新

这是另一个MEF插件,它也有根元素“Help”

在我的主窗体中,我将所有内容添加到MenuStrip

  foreach (var item in MenuItems)
  {
    this.menuStrip1.Items.Add(item.ToolStripItem);
  }

ToolStripMenuItems
不会自动合并?

我非常怀疑是否有自动功能可以做到这一点,因此下面是我如何处理手动解决方案的。有一个陷阱,那就是
ToolStripItem
在任何时候都只能有一个父项。因此,将其添加到现有菜单会将其从其他菜单中删除,您需要考虑到这一点(在我的方法中,通过检查项目是否已经有所有者来完成)。如果这是一个问题,您需要首先克隆子项

编辑:我意识到您可能需要一个递归函数,所以我替换了代码。类MenuItem2包含帮助/speichen/另存为/关于项

public Form1()
{
    InitializeComponent();

    List<IMenu> menuItems = new List<IMenu>() { new UpdateMenuItems(), new MenuItem(), new MenuItem2() };
    MergeMenus(this.menuStrip1.Items, menuItems.Select(m => m.ToolStripItem));
}

/// <summary>
/// Recursive function that merges two ToolStripItem trees into one
/// </summary>
/// <param name="existingItems">Collection of existing ToolStripItems</param>
/// <param name="newItems">Collection of new ToolStripItems. IEnumerable instead of ToolStripItemCollection to allow for items without an owner</param>
private void MergeMenus(ToolStripItemCollection existingItems, IEnumerable<ToolStripItem> newItems)
{
    int count = newItems.Count();
    int removedFromCollection = 0; // keep track of items that are removed from the newItems collection 
    for (int i = 0; i < count; i++)
    {
        ToolStripItem newItem = newItems.ElementAt(i - removedFromCollection);
        bool merged = false;
        string key = newItem.Name; // the items are identified and compared by its name
        if (existingItems.ContainsKey(key))
        {
            ToolStripItem existingItem = existingItems[key];
            if (existingItem != null && existingItem.GetType().Equals(newItem.GetType()))
            {
                // check if the matching items are ToolStripMenuItems. if so, merge their children recursively
                if (newItem is ToolStripMenuItem)
                    MergeMenus(((ToolStripMenuItem)existingItem).DropDownItems, ((ToolStripMenuItem)newItem).DropDownItems.Cast<ToolStripItem>());

                // do not add this particular item (existing item with same name and type found)
                merged = true;
            }
        }

        if (!merged) // newItem does not exist in existingItems (or not as the same type)
        {
            // if there was an owner, the item will be removed from the collection and the next element's index needs to be adjusted
            if (newItem.Owner != null) 
                removedFromCollection++;

            // add item to the existing tree
            existingItems.Add(newItem);
        }
    }
}
public Form1()
{
初始化组件();
List menuItems=new List(){new UpdateMenuItems(),new MenuItem(),new MenuItem2()};
合并菜单(this.menuStrip1.Items,menuItems.Select(m=>m.ToolStripItem));
}
/// 
///将两个ToolStripItem树合并为一个的递归函数
/// 
///现有ToolStripItems的集合
///新ToolStripItems的集合。IEnumerable代替ToolStripItemCollection,以允许没有所有者的项
私有void合并菜单(ToolStripItemCollection existingItems、IEnumerable newItems)
{
int count=newItems.count();
int removedFromCollection=0;//跟踪从newItems集合中删除的项
for(int i=0;i
经过测试,似乎有效:


我实现了一个主菜单,通过IMenuService使用MVVM和Unity。我在同一主题上发布了我自己问题的完整答案(但针对的是菜单而不是工具条)。我认为您可以为ToolStrip做一些与我在代码中所做的非常相似的事情

请参阅以下答案:


嗨,艾伦,谢谢你的回答和MVVM版本,但我在winforms中搜索了一个没有开销的版本:)但是大thx
  foreach (var item in MenuItems)
  {
    this.menuStrip1.Items.Add(item.ToolStripItem);
  }
public Form1()
{
    InitializeComponent();

    List<IMenu> menuItems = new List<IMenu>() { new UpdateMenuItems(), new MenuItem(), new MenuItem2() };
    MergeMenus(this.menuStrip1.Items, menuItems.Select(m => m.ToolStripItem));
}

/// <summary>
/// Recursive function that merges two ToolStripItem trees into one
/// </summary>
/// <param name="existingItems">Collection of existing ToolStripItems</param>
/// <param name="newItems">Collection of new ToolStripItems. IEnumerable instead of ToolStripItemCollection to allow for items without an owner</param>
private void MergeMenus(ToolStripItemCollection existingItems, IEnumerable<ToolStripItem> newItems)
{
    int count = newItems.Count();
    int removedFromCollection = 0; // keep track of items that are removed from the newItems collection 
    for (int i = 0; i < count; i++)
    {
        ToolStripItem newItem = newItems.ElementAt(i - removedFromCollection);
        bool merged = false;
        string key = newItem.Name; // the items are identified and compared by its name
        if (existingItems.ContainsKey(key))
        {
            ToolStripItem existingItem = existingItems[key];
            if (existingItem != null && existingItem.GetType().Equals(newItem.GetType()))
            {
                // check if the matching items are ToolStripMenuItems. if so, merge their children recursively
                if (newItem is ToolStripMenuItem)
                    MergeMenus(((ToolStripMenuItem)existingItem).DropDownItems, ((ToolStripMenuItem)newItem).DropDownItems.Cast<ToolStripItem>());

                // do not add this particular item (existing item with same name and type found)
                merged = true;
            }
        }

        if (!merged) // newItem does not exist in existingItems (or not as the same type)
        {
            // if there was an owner, the item will be removed from the collection and the next element's index needs to be adjusted
            if (newItem.Owner != null) 
                removedFromCollection++;

            // add item to the existing tree
            existingItems.Add(newItem);
        }
    }
}