友元格式枚举用于ComboBoxes,CheckedListBoxes等

需求

我想使用ComboBox从C#中的enum中选择值,或者使用CheckedListBox选择位掩码(对于带有Flags属性的enum )。 我想要一种方法将值添加到控件作为可选项,并干净地告诉用户选择了哪些。

目标1:用户友好

我还希望选择对用户来说清晰而美观。 目前我已经可以将Enum值添加到ComboBoxCheckedListBox ,但Enum.ToString()将返回标识符名称。 Pascal Case对我来说足够好,但不适合我的用户。

目标2:易于编码

我希望这很容易编码。 我的意思很简单 。 我希望这仅仅是一个定义和/或使用任何 enum值的事后想法。

我的解决方案

现在我环顾四周,看到几个不错的解决方案。 其中一些以自己的方式更好,例如, 如果您确实需要放入自己的自定义描述 ,或者更进一步, 支持多种语言 。 你也可以做假枚举 。 但我一直在寻找,并且没有一个像我所写的那样,为了我的目的而优雅和简单的结合。 见下文。

我的解决方案的基础是一个struct ,可以包装Enum值并覆盖ToString()

输入EnumWrapper

 public struct EnumWrapper { private readonly Enum e; public EnumWrapper(Enum e) { this.e = e; } public static implicit operator Enum(EnumWrapper wrapper) { return wrapper.e; } public static explicit operator EnumWrapper(Enum e) { return new EnumWrapper(e); } public override string ToString() { return e.ToStringFriendly(); } } 

方法ToStringFriendly()被定义为Enum上的扩展方法:

 using System.Text.RegularExpressions; public static class _Extensions { public static string ToStringFriendly(this Enum e) { string s = e.ToString(); // enforce a charset: letters, numbers, and underscores s = Regex.Replace(s, "[^A-Za-z0-9_]", ""); // separate numbers from letters s = Regex.Replace(s, "([a-zA-Z])([0-9])", "$1 $2"); // separate letters from numbers s = Regex.Replace(s, "([0-9])([a-zA-Z])", "$1 $2"); // space lowercases before uppercase (word boundary) s = Regex.Replace(s, "([az])([AZ])", "$1 $2"); // see that the nice pretty capitalized words are spaced left s = Regex.Replace(s, "(?!^)([^ _])([AZ][az]+)", "$1 $2"); // replace double underscores with colon-space delimiter s = Regex.Replace(s, "__", ": "); // finally replace single underscores with hyphens s = Regex.Replace(s, "_", "-"); return s; } } 

现在,要将任何Enum值添加到ComboBox,例如,

 comboBox.Items.Add((EnumWrapper)MyEnum.SomeValue); 

并将其取消(当然,在进行空值测试之后):

 MyEnum myValue = (MyEnum)(Enum)(EnumWrapper)comboBox.SelectedItem; 

就是这样。 现在这种方法的优点和缺点是什么?

优点:

  • 您可以(几乎)直接在控件中传入枚举值(几乎)。 只需在EnumWrapper来回EnumWrapper
  • 这适用于所有Pascalshell的Enum值以及一些特殊情况。 一个示例可能是名为MyValue__DescriptionOf123_ENUMValue的值,它将来自ToStringFriendly()作为“我的值:123-ENUM值的描述”
  • 机制( struct和扩展方法)可以编写一次并隐藏起来。 每个Enum都没有额外的编码。 这意味着它可以很好地用于你没有编写的枚举 ,假设Pascal情况,在.NET中是一个很好的假设。 注意:这就是为什么我会说这个答案 ,不管多么优雅,不是比我更好的解决方案,因为它要求你可以为每个Enum添加一个TypeConverter属性。

缺点:

  • 这不支持自定义说明多种语言 。 例如,像Encoding.EBCDIC这样的值将始终作为“EBCDIC”出现,并且不允许您手动键入“扩展二进制编码的十进制交换代码”,更不用说其他语言了。

未来的工作

可以通过更改ToStringFriendly()来添加自定义描述和多语言支持,以便在de-Pascal-casing之前对该值执行语言查找。

有关正则表达式的更多乐趣,请参阅此主题 。