友元格式枚举用于ComboBoxes,CheckedListBoxes等
需求
我想使用ComboBox
从C#中的enum
中选择值,或者使用CheckedListBox
选择位掩码(对于带有Flags
属性的enum
)。 我想要一种方法将值添加到控件作为可选项,并干净地告诉用户选择了哪些。
目标1:用户友好
我还希望选择对用户来说清晰而美观。 目前我已经可以将Enum
值添加到ComboBox
或CheckedListBox
,但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之前对该值执行语言查找。
有关正则表达式的更多乐趣,请参阅此主题 。