【问题标题】:Friendly-Format Enum for use in ComboBoxes, CheckedListBoxes, etc用于 ComboBoxes、CheckedListBoxes 等的友好格式枚举
【发布时间】:2014-09-09 19:04:14
【问题描述】:

要求

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

目标 1:用户友好

我还希望选择对用户来说清晰而漂亮。目前我已经可以将Enum 值添加到ComboBox 或CheckedListBox,但Enum.ToString() 将返回标识符名称。 Pascal Case 对我来说已经足够好了,但对我的用户来说却不是。

目标 2:易于编码

我希望它易于编码。我的意思是简单。我希望这仅仅是定义和/或使用 any enum 值的事后想法。

我的解决方案

现在我环顾四周,看到了几个不错的解决方案。其中一些以自己的方式更好,例如if you really need to put in your own custom descriptions,或者更进一步,support multiple languages。你也可以fake enums。但我一直在寻找,没有一个像我所写的那样完美地结合了优雅和简单——就我的目的而言。见下文。

【问题讨论】:

    标签: c# listview combobox enums checkedlistbox


    【解决方案1】:

    我的解决方案的基础是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, "([a-z])([A-Z])", "$1 $2"); 
    
            // see that the nice pretty capitalized words are spaced left
            s = Regex.Replace(s, "(?!^)([^ _])([A-Z][a-z]+)", "$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 之间来回投射。
    • 这适用于所有 Pascal 大小写的 Enum 值以及一些特殊情况。一个例子可能是一个名为MyValue__DescriptionOf123_ENUMValue 的值,它来自ToStringFriendly(),作为“我的值:123-ENUM 值的描述”。
    • 机制(struct 和扩展方法)可以编写一次并隐藏起来。每个Enum 中没有额外的编码。这意味着它在上面 对于您没有编写的枚举 可以很好地工作,假设 Pascal 情况,这在 .NET 中是一个很好的假设。 注意:这就是为什么我会说this answer,尽管它很优雅,但并不是比我更好的解决方案,因为它要求您可以为每个Enum 添加一个TypeConverter 属性。

    缺点:

    • 这不支持自定义描述或多语言。例如,Encoding.EBCDIC 之类的值将始终以“EBCDIC”的形式出现,并且不允许您手动输入“扩展二进制编码十进制交换码”,更不用说其他语言了。

    未来工作

    可以通过更改 ToStringFriendly() 来添加自定义描述和多语言支持,以便在去帕斯卡大小写之前对该值进行语言查找。

    更多正则表达式的乐趣,请参阅this thread。

    【讨论】:

    • 如果你试图包装一个枚举,很奇怪你正在使用 ToFriendlyString 的扩展方法,该逻辑应该在你的包装器中定义以保持它的包装器。
    • @Cubicle.Jockey:不是这样。这样您就可以随时在任何Enum 上调用ToStringFriendly(),而无需先将其转换为EnumWrapper。我只创建了EnumWrapper 以使ToStringFriendly() 成为组合框等使用的默认值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2010-10-03
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 2014-01-17
    相关资源
    最近更新 更多