with que obtener net manualmente llenar español enum ejemplos descripcion combo .net wpf

.net - que - Enlace de datos de una propiedad enum a un ComboBox en WPF



obtener descripcion de enum c# (13)

Como ejemplo toma el siguiente código:

public enum ExampleEnum { FooBar, BarFoo } public class ExampleClass : INotifyPropertyChanged { private ExampleEnum example; public ExampleEnum ExampleProperty { get { return example; } { /* set and notify */; } } }

Quiero a para vincular la propiedad ExampleProperty a un ComboBox, para que muestre las opciones "FooBar" y "BarFoo" y funcione en modo TwoWay. Optimamente quiero que mi definición de ComboBox se vea algo como esto:

<ComboBox ItemsSource="What goes here?" SelectedItem="{Binding Path=ExampleProperty}" />

Actualmente tengo controladores para los eventos ComboBox.SelectionChanged y ExampleClass.PropertyChanged instalados en mi ventana donde hago el enlace manualmente.

¿Hay alguna forma canónica o mejor? ¿Usaría usualmente convertidores y cómo llenaría ComboBox con los valores correctos? Ni siquiera quiero empezar con i18n ahora.

Editar

Entonces, una pregunta fue respondida: ¿Cómo se rellena el ComboBox con los valores correctos?

Recupere los valores de Enum como una lista de cadenas a través de ObjectDataProvider del método estático Enum.GetValues:

<Window.Resources> <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="ExampleEnumValues"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="ExampleEnum" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </Window.Resources>

Esto puedo usarlo como ItemsSource para mi ComboBox:

<ComboBox ItemsSource="{Binding Source={StaticResource ExampleEnumValues}}"/>


Aquí hay una solución genérica utilizando un método auxiliar. Esto también puede manejar una enumeración de cualquier tipo subyacente (byte, sbyte, uint, long, etc.)

Método de ayuda:

static IEnumerable<object> GetEnum<T>() { var type = typeof(T); var names = Enum.GetNames(type); var values = Enum.GetValues(type); var pairs = Enumerable.Range(0, names.Length) .Select(i => new { Name = names.GetValue(i) , Value = values.GetValue(i) }) .OrderBy(pair => pair.Name); return pairs; }//method

Ver Modelo:

public IEnumerable<object> EnumSearchTypes { get { return GetEnum<SearchTypes>(); } }//property

Caja combo:

<ComboBox SelectedValue ="{Binding SearchType}" ItemsSource ="{Binding EnumSearchTypes}" DisplayMemberPath ="Name" SelectedValuePath ="Value" />


En el modelo de visualización puedes tener:

public MyEnumType SelectedMyEnumType { get { return _selectedMyEnumType; } set { _selectedMyEnumType = value; OnPropertyChanged("SelectedMyEnumType"); } } public IEnumerable<MyEnumType> MyEnumTypeValues { get { return Enum.GetValues(typeof(MyEnumType)) .Cast<MyEnumType>(); } }

En XAML, ItemSource se enlaza a MyEnumTypeValues ​​y SelectedItem se enlaza a SelectedMyEnumType.

<ComboBox SelectedItem="{Binding SelectedMyEnumType}" ItemsSource="{Binding MyEnumTypeValues}"></ComboBox>


En función de la respuesta aceptada pero ahora eliminada proporcionada por here , creé una versión reducida sin algunas de las funciones más avanzadas. Todo el código se incluye aquí para permitirle copiarlo y pegarlo y no quedar bloqueado por el enlace de enlace.

Yo uso System.ComponentModel.DescriptionAttribute que realmente está destinado a las descripciones de tiempo de diseño. Si no te gusta usar este atributo, puedes crear el tuyo, pero creo que usar este atributo realmente hace el trabajo. Si no usa el atributo, el nombre se predeterminará al nombre del valor de enumeración en el código.

public enum ExampleEnum { [Description("Foo Bar")] FooBar, [Description("Bar Foo")] BarFoo }

Aquí está la clase utilizada como fuente de los artículos:

public class EnumItemsSource : Collection<String>, IValueConverter { Type type; IDictionary<Object, Object> valueToNameMap; IDictionary<Object, Object> nameToValueMap; public Type Type { get { return this.type; } set { if (!value.IsEnum) throw new ArgumentException("Type is not an enum.", "value"); this.type = value; Initialize(); } } public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture) { return this.valueToNameMap[value]; } public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture) { return this.nameToValueMap[value]; } void Initialize() { this.valueToNameMap = this.type .GetFields(BindingFlags.Static | BindingFlags.Public) .ToDictionary(fi => fi.GetValue(null), GetDescription); this.nameToValueMap = this.valueToNameMap .ToDictionary(kvp => kvp.Value, kvp => kvp.Key); Clear(); foreach (String name in this.nameToValueMap.Keys) Add(name); } static Object GetDescription(FieldInfo fieldInfo) { var descriptionAttribute = (DescriptionAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute)); return descriptionAttribute != null ? descriptionAttribute.Description : fieldInfo.Name; } }

Puedes usarlo en XAML así:

<Windows.Resources> <local:EnumItemsSource x:Key="ExampleEnumItemsSource" Type="{x:Type local:ExampleEnum}"/> </Windows.Resources> <ComboBox ItemsSource="{StaticResource ExampleEnumItemsSource}" SelectedValue="{Binding ExampleProperty, Converter={StaticResource ExampleEnumItemsSource}}"/>


Esta es una respuesta específica de DevExpress basada en la respuesta más votada por Gregor S. (actualmente tiene 128 votos).

Esto significa que podemos mantener el estilo consistente en toda la aplicación:

Desafortunadamente, la respuesta original no funciona con un ComboBoxEdit de DevExpress sin algunas modificaciones.

Primero, el XAML para el ComboBoxEdit :

<dxe:ComboBoxEdit ItemsSource="{Binding Source={xamlExtensions:XamlExtensionEnumDropdown {x:myEnum:EnumFilter}}}" SelectedItem="{Binding BrokerOrderBookingFilterSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMember="Description" MinWidth="144" Margin="5" HorizontalAlignment="Left" IsTextEditable="False" ValidateOnTextInput="False" AutoComplete="False" IncrementalFiltering="True" FilterCondition="Like" ImmediatePopup="True"/>

No hace falta decir que deberá apuntar xamlExtensions al espacio de nombres que contiene la clase de extensión XAML (que se define a continuación):

xmlns:xamlExtensions="clr-namespace:XamlExtensions"

Y tenemos que apuntar a myEnum al espacio de nombres que contiene la enumeración:

xmlns:myEnum="clr-namespace:MyNamespace"

Entonces, la enumeración:

namespace MyNamespace { public enum EnumFilter { [Description("Free as a bird")] Free = 0, [Description("I''m Somewhat Busy")] SomewhatBusy = 1, [Description("I''m Really Busy")] ReallyBusy = 2 } }

El problema con XAML es que no podemos usar SelectedItemValue , ya que esto genera un error ya que el configurador es inaccesible (bit de un descuido de su parte, DevExpress ). Así que tenemos que modificar nuestro ViewModel para obtener el valor directamente del objeto:

private EnumFilter _filterSelected = EnumFilter.All; public object FilterSelected { get { return (EnumFilter)_filterSelected; } set { var x = (XamlExtensionEnumDropdown.EnumerationMember)value; if (x != null) { _filterSelected = (EnumFilter)x.Value; } OnPropertyChanged("FilterSelected"); } }

Para completar, aquí está la extensión XAML de la respuesta original (ligeramente renombrada):

namespace XamlExtensions { /// <summary> /// Intent: XAML markup extension to add support for enums into any dropdown box, see http://bit.ly/1g70oJy. We can name the items in the /// dropdown box by using the [Description] attribute on the enum values. /// </summary> public class XamlExtensionEnumDropdown : MarkupExtension { private Type _enumType; public XamlExtensionEnumDropdown(Type enumType) { if (enumType == null) { throw new ArgumentNullException("enumType"); } EnumType = enumType; } public Type EnumType { get { return _enumType; } private set { if (_enumType == value) { return; } var enumType = Nullable.GetUnderlyingType(value) ?? value; if (enumType.IsEnum == false) { throw new ArgumentException("Type must be an Enum."); } _enumType = value; } } public override object ProvideValue(IServiceProvider serviceProvider) { var enumValues = Enum.GetValues(EnumType); return ( from object enumValue in enumValues select new EnumerationMember { Value = enumValue, Description = GetDescription(enumValue) }).ToArray(); } private string GetDescription(object enumValue) { var descriptionAttribute = EnumType .GetField(enumValue.ToString()) .GetCustomAttributes(typeof (DescriptionAttribute), false) .FirstOrDefault() as DescriptionAttribute; return descriptionAttribute != null ? descriptionAttribute.Description : enumValue.ToString(); } #region Nested type: EnumerationMember public class EnumerationMember { public string Description { get; set; } public object Value { get; set; } } #endregion } }

Descargo de responsabilidad: No tengo ninguna afiliación con DevExpress. Telerik es también una gran biblioteca.


He creado un proyecto de código abierto CodePlex que hace esto. Puede descargar el paquete NuGet desde here .

<enumComboBox:EnumComboBox EnumType="{x:Type demoApplication:Status}" SelectedValue="{Binding Status}" />


Intenta usar

<ComboBox ItemsSource="{Binding Source={StaticResource ExampleEnumValues}}" SelectedValue="{Binding Path=ExampleProperty}" />


Mi forma favorita de hacer esto es con un ValueConverter para que ItemsSource y SelectedValue se unan a la misma propiedad. Esto no requiere propiedades adicionales para mantener su ViewModel agradable y limpio.

<ComboBox ItemsSource="{Binding Path=ExampleProperty, Converter={x:EnumToCollectionConverter}, Mode=OneTime}" SelectedValuePath="Value" DisplayMemberPath="Description" SelectedValue="{Binding Path=ExampleProperty}" />

Y la definición del convertidor:

public static class EnumHelper { public static string Description(this Enum e) { return (e.GetType() .GetField(e.ToString()) .GetCustomAttributes(typeof(DescriptionAttribute), false) .FirstOrDefault() as DescriptionAttribute)?.Description ?? e.ToString(); } } [ValueConversion(typeof(Enum), typeof(IEnumerable<ValueDescription>))] public class EnumToCollectionConverter : MarkupExtension, IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return Enum.GetValues(value.GetType()) .Cast<Enum>() .Select(e => new ValueDescription() { Value = e, Description = e.Description()}) .ToList(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return null; } public override object ProvideValue(IServiceProvider serviceProvider) { return this; } }

Este convertidor funcionará con cualquier enumeración. ValueDescription es solo una clase simple con una propiedad Value y una propiedad Description . Puede usar una Tuple con Item2 y Item2 , o un KeyValuePair con Key and Value lugar de Value and Description o cualquier otra clase de su elección siempre que tenga un valor de enumeración y una descripción de cadena de ese valor de enumeración.


No sé si es posible solo en XAML, pero intente lo siguiente:

Dale un nombre a tu ComboBox para que puedas acceder a él en el código: "typesComboBox1"

Ahora prueba lo siguiente

typesComboBox1.ItemsSource = Enum.GetValues(typeof(ExampleEnum));


Prefiero no usar el nombre de enum en la interfaz de usuario. Prefiero usar un valor diferente para el usuario ( DisplayMemberPath ) y diferente para el valor (enumeración en este caso) ( SelectedValuePath ). Esos dos valores se pueden empaquetar en KeyValuePair y almacenar en el diccionario.

XAML

<ComboBox Name="fooBarComboBox" ItemsSource="{Binding Path=ExampleEnumsWithCaptions}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding Path=ExampleProperty, Mode=TwoWay}" >

DO#

public Dictionary<ExampleEnum, string> ExampleEnumsWithCaptions { get { return new Dictionary<ExampleEnum, string>() // Fix. Each time new dict.? { {ExampleEnum.FooBar, "Foo Bar"}, {ExampleEnum.BarFoo, "Reversed Foo Bar"}, //{ExampleEnum.None, "Hidden in UI"}, }; } } private ExampleEnum example; public ExampleEnum ExampleProperty { get { return example; } set { /* set and notify */; } }

EDITAR: Compatible con el patrón MVVM.


Puede crear una extensión de marcado personalizado.

Ejemplo de uso:

enum Status { [Description("Available.")] Available, [Description("Not here right now.")] Away, [Description("I don''t have time right now.")] Busy }

En la parte superior de tu XAML:

xmlns:my="clr-namespace:namespace_to_enumeration_extension_class

y entonces...

<ComboBox ItemsSource="{Binding Source={my:Enumeration {x:Type my:Status}}}" DisplayMemberPath="Description" SelectedValue="{Binding CurrentStatus}" SelectedValuePath="Value" />

Y la implementación ...

public class EnumerationExtension : MarkupExtension { private Type _enumType; public EnumerationExtension(Type enumType) { if (enumType == null) throw new ArgumentNullException("enumType"); EnumType = enumType; } public Type EnumType { get { return _enumType; } private set { if (_enumType == value) return; var enumType = Nullable.GetUnderlyingType(value) ?? value; if (enumType.IsEnum == false) throw new ArgumentException("Type must be an Enum."); _enumType = value; } } public override object ProvideValue(IServiceProvider serviceProvider) { var enumValues = Enum.GetValues(EnumType); return ( from object enumValue in enumValues select new EnumerationMember{ Value = enumValue, Description = GetDescription(enumValue) }).ToArray(); } private string GetDescription(object enumValue) { var descriptionAttribute = EnumType .GetField(enumValue.ToString()) .GetCustomAttributes(typeof (DescriptionAttribute), false) .FirstOrDefault() as DescriptionAttribute; return descriptionAttribute != null ? descriptionAttribute.Description : enumValue.ToString(); } public class EnumerationMember { public string Description { get; set; } public object Value { get; set; } } }


Puedes considerar algo como eso:

  1. define un estilo para bloque de texto, o cualquier otro control que quieras usar para mostrar tu enumeración:

    <Style x:Key="enumStyle" TargetType="{x:Type TextBlock}"> <Setter Property="Text" Value="&lt;NULL&gt;"/> <Style.Triggers> <Trigger Property="Tag"> <Trigger.Value> <proj:YourEnum>Value1<proj:YourEnum> </Trigger.Value> <Setter Property="Text" Value="{DynamicResource yourFriendlyValue1}"/> </Trigger> <!-- add more triggers here to reflect your enum --> </Style.Triggers> </Style>

  2. define tu estilo para ComboBoxItem

    <Style TargetType="{x:Type ComboBoxItem}"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <TextBlock Tag="{Binding}" Style="{StaticResource enumStyle}"/> </DataTemplate> </Setter.Value> </Setter> </Style>

  3. agregue un cuadro combinado y cárguelo con sus valores enumerables:

    <ComboBox SelectedValue="{Binding Path=your property goes here}" SelectedValuePath="Content"> <ComboBox.Items> <ComboBoxItem> <proj:YourEnum>Value1</proj:YourEnum> </ComboBoxItem> </ComboBox.Items> </ComboBox>

Si su enum es grande, por supuesto que puede hacer lo mismo en el código, evitando escribir mucho. Me gusta ese enfoque, ya que facilita la localización: define todas las plantillas una vez y, a continuación, solo actualiza los archivos de recursos de cadenas.


Si está utilizando un MVVM, según la respuesta de @rudigrobler, puede hacer lo siguiente:

Agregue la siguiente propiedad a la clase ViewModel

public Array ExampleEnumValues => Enum.GetValues(typeof(ExampleEnum));

Luego en el XAML haz lo siguiente:

<ComboBox ItemsSource="{Binding ExampleEnumValues}" ... />


Utilice ObjectDataProvider:

<ObjectDataProvider x:Key="enumValues" MethodName="GetValues" ObjectType="{x:Type System:Enum}"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="local:ExampleEnum"/> </ObjectDataProvider.MethodParameters> </ObjectDataProvider>

y luego enlazar al recurso estático:

ItemsSource="{Binding Source={StaticResource enumValues}}"

Encuentra esta solución en este blog.