如何最多启用一次菜单项?
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;
我不确定这样做的性能如何,因为您要为每个字符串的第一次出现多次扫描同一个集合。我想这取决于字符串集合的大小,以及您以这种方式启用的菜单项数量。
仅当特定列表框中存在特定类型的文件时,才需要启用某些菜单项。该列表框中可能有大量条目,但即使只有一个条目属于相关文件类型,也需要启用其菜单项。所以,我得到了以下代码:
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;
我不确定这样做的性能如何,因为您要为每个字符串的第一次出现多次扫描同一个集合。我想这取决于字符串集合的大小,以及您以这种方式启用的菜单项数量。