在组合框中显示枚举 [英] Show enum in a comboBox

查看:33
本文介绍了在组合框中显示枚举的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<Grid
    xmlns:local="clr-namespace:SortedEnumInComboBox"
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase">
<Grid.Resources>
  <CollectionViewSource x:Key="ComparatorsView">

    <CollectionViewSource.Source>
      <ObjectDataProvider 
        MethodName="GetNames" 
        ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
          <x:Type TypeName="local:Comparators"/>
        </ObjectDataProvider.MethodParameters>
      </ObjectDataProvider>
    </CollectionViewSource.Source>
  </CollectionViewSource>
</Grid.Resources>

<ComboBox 
  DataContext="{StaticResource ComparatorsView}" 
  ItemsSource="{Binding}" 
  VerticalAlignment="Center" />

public enum Comparators
{
    MinorThan = -1, Equals = 0, GreaterThan = 1
}

我正在尝试在组合框中设置枚举.在 Display 中必须显示 <、= 和 > 并且 SelectedValue 将是 Comparators 值.

I'm trying to set the enum in a comboBox. In Display must show <, =, and > and SelectedValue will be Comparators value.

我不确定我是使用转换器还是什么?

I'm not sure if am I use a converter or what?

推荐答案

这个解决方案 - 不是我创建的 - 允许您将本地化的字符串与枚举值相关联.所以假设我们有一个枚举定义为

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
}

第 1 步:添加一个 Windows 资源 (.resx) 文件,在本例中称为 Resources.resx

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

第 2 步:将字符串资源添加到 EnumTypeName_EnumName 形式的文件中,用于每个枚举值,例如:

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    <

现在我们需要转换器使用的 EnumResourceManagerForLabels 属性,以便它知道要使用哪个资源文件(参见上面的用法):

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; }
    }
}

现在我们需要转换器:

/// <summary>
/// An <see cref="IValueConverter"/> converter that converts between strings and enum types.
/// </summary>
public class EnumLabelConverter : IValueConverter
{
    private readonly Dictionary<object, string> m_labelsByValue = new Dictionary<object, string>();

    private readonly SortedDictionary<string, object> m_valuesByLabel =
        new SortedDictionary<string, object>(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");
                }
            }
        }
    }

    /// <summary>
    /// Gets or sets whether the <see cref="DisplayNames"/> are to be sorted alphanumerically.
    /// </summary>
    /// <value><b>true</b> if the <see cref="DisplayNames"/> are to be sorted alphanumerically; otherwise, <b>false</b>.</value>
    public bool SortDisplayNamesAlphanumerically
    {
        get { return m_sortDisplayNamesAlphanumerically; }
        set { m_sortDisplayNamesAlphanumerically = value; }
    }

    /// <summary>
    /// Gets the display names (labels) for the fields of the associated enum type.
    /// </summary>
    /// <value>The display names.</value>
    public IEnumerable<string> DisplayNames
    {
        get
        {
            return (SortDisplayNamesAlphanumerically)
                       ? m_valuesByLabel.Keys
                       : m_labelsByValue.Values as IEnumerable<string>;
        }
    }

    #region IValueConverter Members

    /// <summary>
    /// Converts the enum value into a string.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="targetType">Type of the target.</param>
    /// <param name="parameter">The parameter.</param>
    /// <param name="culture">The culture.</param>
    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<string>();

                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;
    }

    /// <summary>
    /// Converts the string back into an enum of the appropriate type.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="targetType">Type of the target.</param>
    /// <param name="parameter">The parameter.</param>
    /// <param name="culture">The culture.</param>
    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
}

最后是一个用法示例:

<Grid>
    <Grid.Resources>
        <Converters:EnumLabelConverter x:Key="OperatorConverter" EnumType="{x:Type ViewModel:Operator}" />
    </Grid.Resources>

    <StackPanel>
        <!-- Bind text block to 'GreaterThan' -->
        <TextBlock Text="{Binding Source={x:Static ViewModel:Operator.GreaterThan}, Converter={StaticResource OperatorConverter}}"/>

        <!-- Bind text block to datacontext -->
        <TextBlock Text="{Binding SelectedOperator, Converter={StaticResource OperatorConverter}}"/>

        <!-- Bind combo box to localized enums and bind to datacontext -->
        <ComboBox 
            SelectedValue="{Binding SelectedOperator, Converter={StaticResource OperatorConverter}}" 
            ItemsSource="{Binding Source={StaticResource OperatorConverter}, Path=DisplayNames}"/>

        <!-- Bind combo box to localized enums and select 'GreaterThan' -->
        <ComboBox 
            SelectedValue="{Binding Source={x:Static ViewModel:Operator.GreaterThan}, Converter={StaticResource OperatorConverter}, Mode=OneWay}" 
            ItemsSource="{Binding Source={StaticResource OperatorConverter}, Path=DisplayNames}"/>
    </StackPanel>
</Grid>

视图模型(使用 MVVM 灯)在哪里:

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); }
    }
}

这篇关于在组合框中显示枚举的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆