我有一个ContextMenuStrip
控件,其中包含多个菜单项A,B,C,D,E,并在项目C前后添加了分隔符。
在运行时,我根据某些条件在Opening
事件中动态决定是否显示菜单项C。
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
toolStripMenuItemC.Visible = SomeCondition;
}
当在运行时显示菜单并且C项被隐藏时,两个分隔符都是可见的,看起来很丑。
是否有一些内置机制可以自动将多个连续的菜单分隔符组合为一个?例如,Delphi中的VCL框架为此具有TPopupMenu.AutoLineReduction
属性。
当然可以为菜单编写特定的逻辑,以查看哪些菜单项可见,然后确定要显示的分隔符。但是,项目越多,分隔符越多,此代码将变得越复杂。每次在菜单中添加,删除或移动菜单项时,都必须更新代码。
我正在寻找一种在不知道菜单中特定项目的情况下可以在任何菜单上使用的通用方法。我更喜欢开箱即用的WinForms中已经包含的某种方式,但是您也可以使用自己的工具功能来清除菜单中的分隔符。
答案 0 :(得分:1)
由于我尚未在WinForms中找到内置的方法来完成此操作,因此我编写了以下实用程序函数:
public static class ToolStripExtensions
{
/// <summary>
/// Automatically show/hide separator in toolstrips (Menus, toolbars, etc).
/// This will hide / show separators based on the other toolstripitems in the collections.
/// A separator will be hidden if it would be the first visible entry in the list.
/// A separator will be hidden if it would be the last visible entry in the list.
/// A separator will be hidden if it would appear right after another separator.
/// All other separatos will be shown.
/// </summary>
/// <param name="items">A collection of ToolStripItems</param>
/// <param name="includeSubmenus">If true, also cleanup separators in submenus</param>
public static void CleanUpSeparators(this ToolStripItemCollection items, bool includeSubmenus = true)
{
// Will be true when we have last seen a visible item
// which is not a separator
bool canInsertSeparator = false;
List<ToolStripSeparator> keepers = new List<ToolStripSeparator>();
List<ToolStripSeparator> gonners = new List<ToolStripSeparator>();
ToolStripSeparator lastSeparator = null;
// Decide which separators should stay and which should go
for (int i = 0; i < items.Count; i++)
{
ToolStripItem item = items[i];
if (item is ToolStripSeparator)
{
if (canInsertSeparator)
{
keepers.Add(item as ToolStripSeparator);
lastSeparator = item as ToolStripSeparator;
canInsertSeparator = false;
}
else
{
gonners.Add(item as ToolStripSeparator);
}
}
else
{
// After seeing at least one visible item, we can add a new separator again
if (item.Available)
{
canInsertSeparator = true;
}
}
// Recursion
if (includeSubmenus && item is ToolStripDropDownItem)
{
(item as ToolStripDropDownItem).DropDownItems.CleanUpSeparators(true);
}
}
if (!canInsertSeparator && lastSeparator != null)
{
// The last separator has no following visible other entries,
// so we don't want it
gonners.Add(lastSeparator);
}
// Show and hide the separators
// First show, then hide, because it is possible
// a separator at the end of the menu is in both lists
// and it should be hidden
foreach (var separator in keepers)
{
separator.Visible = true;
}
foreach (var separator in gonners)
{
separator.Visible = false;
}
}
}
它会这样使用:
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
toolStripMenuItemC.Visible = SomeCondition;
contextMenuStrip1.Items.CleanUpSeparators();
}
答案 1 :(得分:0)
尝试一下,它以不同的方式工作,根据要隐藏的ToolStripMenuItem
的相对位置显示或隐藏ToolStripSeparator
和ToolStripMenuItem
:
在以下情况下显示/隐藏ToolStripSeparator
:
ToolStripSeparator
ToolStripSeparator
ToolStripSeparator
方法调用:ShowHideMenuItem([ParentMenu], [ToolStripMenuItem], [true|false])
ShowHideMenuItem(ToolStripMenuItem1, ToolStripMenuItem5, true);
private void ShowHideMenuItem(ToolStripMenuItem ParentMenu, ToolStripMenuItem MenuItem, bool ShowOrHide)
{
if (!ParentMenu.HasDropDownItems) return;
int itemIndex = ParentMenu.DropDownItems.IndexOf(MenuItem);
if (ParentMenu.DropDownItems.Count > 1)
{
if (itemIndex == 0 &&
ParentMenu.DropDownItems[itemIndex + 1].GetType() == typeof(ToolStripSeparator)) {
ParentMenu.DropDownItems[itemIndex + 1].Visible = ShowOrHide;
}
else if (itemIndex == ParentMenu.DropDownItems.Count - 1 &&
ParentMenu.DropDownItems[itemIndex - 1].GetType() == typeof(ToolStripSeparator)) {
ParentMenu.DropDownItems[itemIndex - 1].Visible = ShowOrHide;
}
else if (ParentMenu.DropDownItems[itemIndex + 1].GetType() == typeof(ToolStripSeparator) &&
ParentMenu.DropDownItems[itemIndex - 1].GetType() == typeof(ToolStripSeparator)) {
ParentMenu.DropDownItems[itemIndex + 1].Visible = ShowOrHide;
ParentMenu.DropDownItems[itemIndex - 1].Visible = ShowOrHide;
}
}
MenuItem.Visible = ShowOrHide;
}