目前,我尝试将不同的ToolStripMenuItems
合并为一个MenuStrip
。因此我创建了一个名为IMenu
的接口。这包括来自MEF插件的ToolStripMenuItem
,应该加载到Main-Window-Menustrip中。问题是,如果我运行应用程序,我会使用相同名称的MenuStrip
两个DropDown元素。但我想要的是我可以将MEF插件的菜单绑定到应用程序的MenuStrip中,而无需双重输入。
如何为MEF插件制作一个好的菜单结构?
示例:我从主应用程序中获得了这些条目
文件
| - >新
| - >保存
| - >进口
| - >出口
然后我为Import / Export创建了一个特定类型的插件。因此,我必须在导入/导出下动态添加菜单。但是怎么样?你的解决方案如何?
文件
| - >新
| - >保存
| - >进口
| ----->到词
| - >出口
| ----->从Word
这是我的代码: 首先是插件的接口
public interface IMenu
{
ToolStripMenuItem ToolStripItem { get; }
}
这是菜单项
的插件示例帮助
| - >更新
[Export(typeof(IMenu))]
class UpdateMenuItems : IMenu
{
System.Windows.Forms.ToolStripMenuItem helpMenuItem;
System.Windows.Forms.ToolStripMenuItem updateMenuItem;
public System.Windows.Forms.ToolStripMenuItem ToolStripItem
{
get { return helpMenuItem; }
}
public UpdateMenuItems()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.updateMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.updateMenuItem.Name = "Update";
this.updateMenuItem.Size = new System.Drawing.Size(94, 20);
this.updateMenuItem.Text = "Update";
this.updateMenuItem.MergeIndex = 1;
this.updateMenuItem.MergeAction = System.Windows.Forms.MergeAction.Insert;
this.updateMenuItem.Click += updateMenuItem_Click;
this.helpMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.helpMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.updateMenuItem});
this.helpMenuItem.Name = "aboutToolStripMenuItem";
this.helpMenuItem.Size = new System.Drawing.Size(44, 20);
this.helpMenuItem.MergeAction = System.Windows.Forms.MergeAction.Insert;
this.helpMenuItem.Text = "Help";
}
void updateMenuItem_Click(object sender, EventArgs e)
{
UpdateController update = new UpdateController();
update.Execute();
}
这是另一个MEF插件,它也有根元素“帮助”
[Export(typeof(IMenu))]
class MenuItem : IMenu
{
public ToolStripMenuItem ToolStripItem
{
get { return testItem; }
}
private System.Windows.Forms.ToolStripMenuItem testItem;
private System.Windows.Forms.ToolStripMenuItem unterpunk1;
private System.Windows.Forms.ToolStripMenuItem unterpunk2;
public MenuItem()
{
InitializeComponent();
}
public void InitializeComponent()
{
this.testItem = new System.Windows.Forms.ToolStripMenuItem();
this.testItem.Name = "aboutToolStripMenuItem";
this.testItem.Size = new System.Drawing.Size(94, 20);
this.testItem.Text = "Help";
this.testItem.Click += testItem_Click;
unterpunk1 = new ToolStripMenuItem();
unterpunk1.Text = "Speichern";
unterpunk1.MergeAction = MergeAction.Insert;
unterpunk1.MergeIndex = 1;
testItem.DropDownItems.Add(unterpunk1);
unterpunk2 = new ToolStripMenuItem();
unterpunk2.Text = "Prüfen";
unterpunk2.MergeAction = MergeAction.Insert;
unterpunk2.MergeIndex = 2;
testItem.DropDownItems.Add(unterpunk2);
}
void testItem_Click(object sender, EventArgs e)
{
//
}
在我的主要表单中,我将所有内容添加到MenuStrip。
foreach (var item in MenuItems)
{
this.menuStrip1.Items.Add(item.ToolStripItem);
}
ToolStripMenuItems
不会自动合并?
答案 0 :(得分:2)
我非常怀疑有一个自动功能可以做到这一点,所以这就是我如何处理手动解决方案。有一个陷阱,即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);
}
}
}
经过测试并且似乎有效:
答案 1 :(得分:1)
我实现了一个主菜单,通过IMenuService使用MVVM和Unity。我在同一个主题上发布了一个相当完整的答案来解答我自己的问题(但是对于菜单而不是工具条)。我认为你可以为ToolStrip做一些非常类似于我在代码中所做的事情。
请参阅以下答案: