Es posible el uso de la ObjectDataProvider método para enlazar un ListBox a un enum, y el estilo de alguna manera para mostrar la Descripción attriibute? Si es así, cómo se podría ir sobre hacer esto…?

4 Comentarios

  1. 90

    Sí, es posible. Esto va a hacer. Dicen que tenemos la enumeración

    public enum MyEnum
    {
        [Description("MyEnum1 Description")]
        MyEnum1,
        [Description("MyEnum2 Description")]
        MyEnum2,
        [Description("MyEnum3 Description")]
        MyEnum3
    }

    Entonces podemos usar la ObjectDataProvider como

    xmlns:MyEnumerations="clr-namespace:MyEnumerations"
    <ObjectDataProvider MethodName="GetValues"
                    ObjectType="{x:Type sys:Enum}"
                    x:Key="MyEnumValues">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="MyEnumerations:MyEnum" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

    Y para el control ListBox hemos establecido la ItemsSource a MyEnumValues y aplicar un ItemTemplate con un Convertidor.

    <ListBox Name="c_myListBox" SelectedIndex="0" Margin="8"
            ItemsSource="{Binding Source={StaticResource MyEnumValues}}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    Y en el convertidor tenemos la descripción y volver

    public class EnumDescriptionConverter : IValueConverter
    {
        private string GetEnumDescription(Enum enumObj)
        {
            FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
    
            object[] attribArray = fieldInfo.GetCustomAttributes(false);
    
            if (attribArray.Length == 0)
            {
                return enumObj.ToString();
            }
            else
            {
                DescriptionAttribute attrib = attribArray[0] as DescriptionAttribute;
                return attrib.Description;
            }
        }
    
        object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Enum myEnum = (Enum)value;
            string description = GetEnumDescription(myEnum);
            return description;
        }
    
        object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return string.Empty;
        }
    }

    La GetEnumDescription método probablemente debería ir a otro lugar, pero usted consigue la idea 🙂

    • Gracias, va a dar a este un intento ahora 🙂
    • El amor es, ganked ella. He utilizado un poco de linq to par GetEnumDescription, usted puede enganchar aquí pastebin.com/XLm9hbhG
    • Así que usted tiene que hacer un convertidor para cada tipo de enum?
    • No, en este ejemplo, el convertidor está aportando valor a MyEnum pero puede también utilizar Enum si quieres un conversor genérico
    • +1 de mí. Simple y se hace el trabajo, justo lo que necesitaba. Por CIERTO, para aquellos que necesitan de la localización, Sacha Peluquería tiene un artículo sobre CodeProject.com que implementa una más compleja solución que soporta la localización.
    • Ten en cuenta que tienes que crear una instancia del convertidor como un recurso, por ejemplo: <helper:EnumDescriptionConverter x:Key="HEnumDescriptionConverter" />
    • Esto va a romper si usted tiene un atributo diferente en el enum – me gustaría sugerir cambios en el código para attrib = attribArray.OfType<DescriptionAttribute>().FirstOrDefault(); y la comprobación de null en lugar de ello, ya que es más robusto.

  2. 2

    Otra solución sería una costumbre MarkupExtension que genera los elementos de tipo enum. Esto hace que el xaml más compacto y legible.

    using System.ComponentModel;
    
    namespace EnumDemo
    {
        public enum Numbers
        {
            [Description("1")]
            One,
    
            [Description("2")]
            Two,
    
            Three,
        }
    }

    Ejemplo de uso:

    <Window x:Class="EnumDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:EnumDemo">
    
        <ListBox ItemsSource="{local:EnumToCollection EnumType={x:Type local:Numbers}}"/>
    
    </Window>

    MarkupExtension aplicación

    using System;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows.Markup;
    
    namespace EnumDemo
    {
        public class EnumToCollectionExtension : MarkupExtension
        {
            public Type EnumType { get; set; }
    
            public override object ProvideValue(IServiceProvider serviceProvider)
            {
                if (EnumType == null) throw new ArgumentNullException(nameof(EnumType));
    
                return Enum.GetValues(EnumType).Cast<Enum>().Select(EnumToDescriptionOrString);
            }
    
            private string EnumToDescriptionOrString(Enum value)
            {
                return value.GetType().GetField(value.ToString())
                           .GetCustomAttributes(typeof(DescriptionAttribute), false)
                           .Cast<DescriptionAttribute>()
                           .FirstOrDefault()?.Description ?? value.ToString();
            }
        }
    }
  3. 1

    Puede definir un archivo de recursos en el proyecto (*.archivo resx). En este archivo se deben definir «clave-valor-pares», algo como esto:

    "YellowCars" : "Yellow Cars",
    "RedCars" : "Red Cars",

    y así sucesivamente…

    Las claves son iguales a su enum-entradas, algo como esto:

    public enum CarColors
    {
        YellowCars,
        RedCars
    }

    y así sucesivamente…

    Al uso de WPF que usted puede implementar en su XAML Código, algo como esto:

    <ComboBox ItemsSource="{Binding Source={StaticResource CarColors}}" SelectedValue="{Binding CarColor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Converter={StaticResource CarColorConverter}}" />
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

    A continuación, usted debe escribir su Convertidor, algo como esto:

    using System;
    using System.Globalization;
    using System.Resources;
    using System.Windows.Data;
    
    public class CarColorConverter : IValueConverter
    {
        private static ResourceManager CarColors = new ResourceManager(typeof(Properties.CarColors));
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var key = ((Enum)value).ToString();
            var result = CarColors.GetString(key);
            if (result == null) {
                result = key;
            }
    
            return result;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    Mi respuesta viene en 7 años a la tarde; -), Pero tal vez puede ser utilizado por otra persona!

Dejar respuesta

Please enter your comment!
Please enter your name here