如何最多启用一次菜单项?

How can I enable the menu items at most once?

仅当特定列表框中存在特定类型的文件时,才需要启用某些菜单项。该列表框中可能有大量条目,但即使只有一个条目属于相关文件类型,也需要启用其菜单项。所以,我得到了以下代码:

foreach (String pt in platypusTables)
{
    if (pt.IndexOf("Duckbill") == 0)
    {
        menuItemSEND_Duckbills.Enabled = true;
    }
    if (pt.IndexOf("Platypus") == 0)
    {
        menuItemSEND_Platypi.Enabled = true;
    }
    listBoxWork.Items.Add(pt);
}

问题是菜单项可能被启用了数百次。我更喜欢只设置一次的优雅,但想不出一个明智的方法来实现这一点。我可以这样做:

foreach (String pt in platypusTables)
{
    if ((pt.IndexOf("Duckbill") == 0) && (!(menuItemSEND_Duckbills.Enabled)))
    {
        menuItemSEND_Duckbills.Enabled = true;
    }
    if ((pt.IndexOf("Platypus") == 0) && (!(menuItemSEND_Platypi.Enabled)))
    {
        menuItemSEND_Platypi.Enabled = true;
    }
    listBoxWork.Items.Add(pt);
}

...但我怀疑它的性能是否更高,也许更差。我是否坚持使用可能一次又一次启用的菜单项,或者是否有解决这个难题的方法?

从某种意义上说,您被卡住了,但该作业 并不昂贵。 if 语句不会更有效,因为控件已经 执行 检查:Reference Source

可以做的一件事是设置标志,然后将它们放在一起。例如,假设您有 8 个选项,您可以设置二进制映射:

Dictionary<String, byte> typeMapping = new Dictionary<String, byte>();
typeMapping.Add("FileType1", 0x01); //00000001

意味着只应为该文件类型打开最后一个选项。然后,您可以列出您的清单:

byte finalTypes = 0x00;
foreach (string type in list.Select(f => f.FileType).Distinct())
    finalTypes |= typeMapping[type];

然后你只需要遍历 that 检查位标志集。

byte checkByte = 0x80;
while (checkByte != 0)
{
   if (finalTypes & checkByte != 0)
      //Bit set, enable

    checkByte = checkByte >> 1;
}

这样,您只需真正检查启用并设置一次实际值。根据我的经验,这是 combing/checking 大量标志的一种非常有效的方法。唯一的缺点是,一旦你获得超过 64 个选项,你就会从足够大的数据类型开始 运行 :(.

可能 能够使用 [Flags] 枚举来做同样的事情,尽管我相信它受到类似的限制。如果您想走这条路,请考虑一下。

尽管如此,这确实很复杂,而且可能不值得它 可能 给你的任何微不足道的收获。如果您没有好的评论(尤其是类型映射),它也很难阅读。分配离开!

如果你只想启用项目(而不是禁用),你可以使用类似的东西:

foreach (String pt in platypusTables)
{
    menuItemSEND_Duckbills.Enabled = menuItemSEND_Duckbills.Enabled || (pt.IndexOf("Duckbill") == 0);
    menuItemSEND_Platypi.Enabled = menuItemSEND_Platypi.Enabled || (pt.IndexOf("Platypus") == 0);
    listBoxWork.Items.Add(pt);
}

另一种方法是使用扩展方法:

foreach (String pt in platypusTables)
{
    menuItemSEND_Duckbills.EnableIfNot(pt,"Duckbill");
    menuItemSEND_Platypi.EnabledIfNot(pt,"Platypus");
    listBoxWork.Items.Add(pt);
}

//extention method, supposing a MenuItem class
public static void EnableIfNot(this MenuItem menuItem, string table, string nameToSearch)
{
     if(!menuItem.Enabled && table.IndexOf(nameToSearch)==0)
     {
             menuItem.Enabled=true;
     }
}

希望对您有所帮助

您可以在集合中扫描以您要查找的每种类型开头的任何字符串。对 Any() 的调用将在找到匹配项时停止,并且您最多启用每个菜单一次。

menuItemSEND_Duckbills.Enabled = platypusTables.Any(p => p.StartsWith("Duckbill"));
menuItemSEND_Platypi.Enabled = platypusTables.Any(p => p.StartsWith("Platypus"));

listBoxWork.DataSource = platypusTables;

我不确定这样做的性能如何,因为您要为每个字符串的第一次出现多次扫描同一个集合。我想这取决于字符串集合的大小,以及您以这种方式启用的菜单项数量。