在组合框显示枚举 [英] Show enum in a comboBox
问题描述
<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
}
我想设置一个组合框的枚举。显示器必须显示&LT,=,和大于;
和的SelectedValue
将比较
值。
我不知道如果我是使用转换器还是什么?
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; }
}
}
现在我们需要的转换器:
Now we need the converter:
/// <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屋!