Show enum in a comboBox

前端 未结 1 848
执念已碎
执念已碎 2020-12-20 08:44


        
1条回答
  •  误落风尘
    2020-12-20 09:23

    This solution - which was not created by me - allows you to associate localized strings with enum values. So assuming we have an enum defined as

    [EnumResourceManagerForLabels(typeof(Resources))]
    public enum Operator
    {
        EqualTo = 0,
        GreaterThan = 1,
        LessThan = -1
    }
    

    Step 1: Add a Windows resource (.resx) file called in this case Resources.resx

    Step 2: Add string resources to the file of the form EnumTypeName_EnumName for each enum value, e.g:

    Operator_EqualTo     =
    Operator_GreaterThan >
    Operator_LessThan    <
    

    Now we need the EnumResourceManagerForLabels attribute which is used by our converter so it know which resource file to use (see usage above):

    [AttributeUsage(AttributeTargets.Enum)]
    public sealed class EnumResourceManagerForLabelsAttribute : Attribute
    {
        private readonly Type m_resourceManagerType;
    
        public EnumResourceManagerForLabelsAttribute(Type resourceManagerType)
        {
            m_resourceManagerType = resourceManagerType;
        }
    
        public Type ResourceManagerType
        {
            get { return m_resourceManagerType; }
        }
    }
    

    Now we need the converter:

    /// 
    /// An  converter that converts between strings and enum types.
    /// 
    public class EnumLabelConverter : IValueConverter
    {
        private readonly Dictionary m_labelsByValue = new Dictionary();
    
        private readonly SortedDictionary m_valuesByLabel =
            new SortedDictionary(StringComparer.Ordinal);
    
        private Type m_enumType;
        private bool m_labelsAreUnique;
        private bool m_sortDisplayNamesAlphanumerically = true;
    
        public Type EnumType
        {
            get { return m_enumType; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
    
                if (m_enumType != value)
                {
                    m_valuesByLabel.Clear();
                    m_labelsByValue.Clear();
                    m_labelsAreUnique = true;
                    m_enumType = value;
    
                    if (m_enumType.IsEnum)
                    {
                        const bool lookAtInheritedAttributes = false; // Ignored.
                        var enumResourceManagerAttribute =
                            m_enumType.GetCustomAttributes(typeof (EnumResourceManagerForLabelsAttribute),
                                                           lookAtInheritedAttributes).FirstOrDefault() as
                            EnumResourceManagerForLabelsAttribute;
    
                        ResourceManager manager;
                        if (enumResourceManagerAttribute != null)
                        {
                            manager = new ResourceManager(enumResourceManagerAttribute.ResourceManagerType);
                        }
                        else
                        {
                            // We use the invariant culture for detailing exceptions caused by programmer error.
                            throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                                                                      "The enum '{0}' does not have a '{1}' attribute.",
                                                                      m_enumType.FullName,
                                                                      typeof (EnumResourceManagerForLabelsAttribute).
                                                                          FullName), "value");
                        }
    
                        // For each field, retrieve the label from the resource manager.
                        foreach (FieldInfo fieldInfo in m_enumType.GetFields(BindingFlags.Public | BindingFlags.Static))
                        {
                            // We use the invariant culture to compute the string to use as the key to the resource.
                            string resourceKey = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", m_enumType.Name,
                                                               fieldInfo.Name);
    
                            string description = manager.GetString(resourceKey);
    
                            if (string.IsNullOrEmpty(description))
                            {
                                // We use the invariant culture for detailing exceptions caused by programmer error.
                                throw new InvalidOperationException(
                                    string.Format(CultureInfo.InvariantCulture,
                                                  "The label for the field {0} of the enum {1} is either null, empty, or the string resource with key {2} is absent from the {3} resource file.",
                                                  fieldInfo.Name,
                                                  m_enumType.FullName,
                                                  resourceKey,
                                                  manager.BaseName));
                            }
    
                            object fieldValue = fieldInfo.GetValue(null);
    
                            if (m_valuesByLabel.ContainsKey(description))
                            {
                                // We already have an entry with that label so we cannot provide ConvertBack()
                                // functionality because of the ambiguity.
                                m_labelsAreUnique = false;
                            }
                            else
                            {
                                m_valuesByLabel.Add(description, fieldValue);
                            }
    
                            m_labelsByValue.Add(fieldValue, description);
                        }
                    }
                    else
                    {
                        // We use the invariant culture for detailing exceptions caused by programmer error.
                        throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                                                                  "The type '{0}' is not an enum type.", m_enumType.Name),
                                                    "value");
                    }
                }
            }
        }
    
        /// 
        /// Gets or sets whether the  are to be sorted alphanumerically.
        /// 
        /// true if the  are to be sorted alphanumerically; otherwise, false.
        public bool SortDisplayNamesAlphanumerically
        {
            get { return m_sortDisplayNamesAlphanumerically; }
            set { m_sortDisplayNamesAlphanumerically = value; }
        }
    
        /// 
        /// Gets the display names (labels) for the fields of the associated enum type.
        /// 
        /// The display names.
        public IEnumerable DisplayNames
        {
            get
            {
                return (SortDisplayNamesAlphanumerically)
                           ? m_valuesByLabel.Keys
                           : m_labelsByValue.Values as IEnumerable;
            }
        }
    
        #region IValueConverter Members
    
        /// 
        /// Converts the enum value into a string.
        /// 
        /// The value.
        /// Type of the target.
        /// The parameter.
        /// The culture.
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // We intentionally do not assert anything about 'value', so that we fail gracefully if the binding was not hooked up correctly.
            // (this may be the case when first loading some UI).
            object result = DependencyProperty.UnsetValue;
    
            if (value != null)
            {
                // See if we have been given a single value or a collection of values.
                var values = value as IEnumerable;
                if (values != null)
                {
                    var labels = new List();
    
                    foreach (object item in values)
                    {
                        string labelString;
    
                        if (m_labelsByValue.TryGetValue(item, out labelString))
                        {
                            labels.Add(labelString);
                        }
                        else
                        {
                            throw new NotSupportedException();
                        }
                    }
    
                    result = labels;
                }
                else
                {
                    string labelString;
                    result = m_labelsByValue.TryGetValue(value, out labelString) ? labelString : DependencyProperty.UnsetValue;
                }
            }
    
            return result;
        }
    
        /// 
        /// Converts the string back into an enum of the appropriate type.
        /// 
        /// The value.
        /// Type of the target.
        /// The parameter.
        /// The culture.
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!m_labelsAreUnique)
            {
                throw new InvalidOperationException(
                    GetType().Name + ".ConvertBack() requires that enum labels are unique to avoid ambiguity.");
            }
    
            // We intentionally do not assert anything about 'value', so that we fail gracefully if the binding was not hooked up correctly,
            // (this may be the case when first loading some UI).
            object enumValue;
            var labelString = value as string;
    
            if (!string.IsNullOrEmpty(labelString))
            {
                if (!m_valuesByLabel.TryGetValue(labelString, out enumValue))
                {
                    // The value for the label could not be found.
                    enumValue = DependencyProperty.UnsetValue;
                }
            }
            else
            {
                // The value we were passed was a null or empty string, or not a string.
                enumValue = DependencyProperty.UnsetValue;
            }
    
            return enumValue;
        }
    
        #endregion
    }
    

    and finally an example of usage:

    
        
            
        
    
        
            
            
    
            
            
    
            
            
    
            
            
        
    
    

    Where the view model (using MVVM light) is:

    public class EnumBindingSampleViewModel : ViewModelBase
    {
        private Operator _selectedOperator;
        public Operator SelectedOperator
        {
            get { return _selectedOperator; }
            set { Set(()=>SelectedOperator, ref _selectedOperator, value); }
        }
    }
    

    0 讨论(0)
提交回复
热议问题