WPF – Databinding con Enums

Sin duda, al trabajar con WPF empleando algún patrón de desarrollo tal como MVVM empezamos a ser conscientes de las grandes posibilidades que nos ofrece su engine de Databinding. En esta ocasión me gustaría tratar como realizar databinding empleando como fuente un tipo enumerado sobre un Combo. Empezaremos viendo el resultado final de la aplicación de ejemplo para ponernos en contexto. Se trata de un ejemplo muy simple en el únicamente contaremos con un combo que muestra los tres elementos declarados en un Enum. WPF - Databinding con un Enum Show me the code! La definición del enumerado la realizaremos de la siguiente forma.

using System.ComponentModel;

namespace Wpf.BindToEnum
{
    public enum RankingType
    {
        [Description("Semana")]
        Week,
        [Description("Mes")]
        Month,
        [Description("Año")]
        Year
    }
}

Lo único que hacemos un poco “especial” es añadir referencia a “System.ComponentModel” para poder emplear el atributo “Description” en el que indicaremos el texto a mostrar para cada valor del enum. Llegados a este punto la pregunta es ¿cómo mostraremos el valor de los atributos el combo? La clave está en el uso de los “Value Converters“. Definiremos dos clases con el siguiente código. En primer caso nuestro “Value Converter”.

using System.Globalization;
using System.Windows.Data;

namespace Wpf.BindToEnum
{
    public class RankingTypeToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (string.IsNullOrEmpty(value.ToString()))  
                return RankingType.Month;

            return (StringToEnum<RankingType>(value.ToString())).GetDescription(); 
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (string.IsNullOrEmpty(value.ToString())) 
                return RankingType.Month;

            return StringToEnum<RankingType>(value.ToString());
        }

        public static T StringToEnum<T>(string name)
        {
            return (T)Enum.Parse(typeof(T), name);
        }
    }
}

Y por otro lado una clase con un método de extensión con el siguiente código:

using System;
using System.ComponentModel;
using System.Reflection;

namespace Wpf.BindToEnum
{
    public static class EnumGetDescription
    {
        public static string GetDescription(this 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;
            }
        }
    }
}

El “Value Converter” se encarga de realizar la conversión de un valor de origen a un valor de destino. El valor de destino se obtiene, tal y como se ve en la clase “EnumGetDescription”, en el valor del atributo declarado en el enum. Por último, sólo nos falta saber cómo se empleada todo esto en nuestra vista con código XAML.

<Window x:Class="Wpf.BindToEnum.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:System="clr-namespace:System;assembly=mscorlib" 
        xmlns:local="clr-namespace:Wpf.BindToEnum">
    <Window.Resources>
        <ResourceDictionary>
            <ObjectDataProvider x:Key="RankingDataSource" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
                <ObjectDataProvider.MethodParameters>
                    <x:Type TypeName="local:RankingType" />
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
            <local:RankingTypeToStringConverter x:Key="RankingTypeToStringConverter"/>
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource RankingDataSource}}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Converter={StaticResource RankingTypeToStringConverter}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>

En primer lugar añadimos las referencias necesarias en las siguientes líneas:

        
xmlns:System="clr-namespace:System;assembly=mscorlib" 
        xmlns:local="clr-namespace:Wpf.BindToEnum"

A continuación declaramos un objeto de tipo “ObjectDataProvider”, así como a nuestro “Value Converter”.

        <ResourceDictionary>
            <ObjectDataProvider x:Key="RankingDataSource" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
                <ObjectDataProvider.MethodParameters>
                    <x:Type TypeName="local:RankingType" />
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
            <local:RankingTypeToStringConverter x:Key="RankingTypeToStringConverter"/>
        </ResourceDictionary>

Por último, añadimos el Combobox que hará uso de de los Resources declarados anteriormente:

        <ComboBox ItemsSource="{Binding Source={StaticResource RankingDataSource}}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Converter={StaticResource RankingTypeToStringConverter}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

Puedes descartar el código completo del ejemplo en mi cuenta de GitHub.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s