13 maja 2016

Bind to enum C#

Rozważmy taką sytuację. Mamy jakiś Enum i chcemy wybrać jego wartość przy pomocy listy wyboru. Chcemy, aby użytkownik widział opisy dla każdej wartości. Tymczasem w tle dokonujemy Bindowania Enum tak, aby wszystkie wartości naszego typu wyliczeniowego zostały wyświetlone w liście wraz z opisami.

Definicja enum

Definiujemy nasz typ, a razem z nim opisy. Opis nie jest ograniczony do jednego słowa oraz znaków ASCII. Jeśli nie zdefiniujemy opisu, wówczas wykorzystana zostanie nazwa pola.

internal enum ExampleEnum
{
 Element1,
 
 [Description("Skoplikowany opis ze spacjami [2]")]
 Element2,
 
 [Description("opis zawierajacy polskie znaki: ĄĆĘŁŃ")]
 Element3, 
 
 Element4,
}

Bindowanie

Kiedy chcemy wyświetlić listę dostępnych wartości dla typu Enum, robimy to tak:

var elements = EnumHelper.GetValueDescriptionEnumerable<ExampleEnum>()
    .Select(a => new {wartosc = a.Item1, opis = a.Item2})
    .ToList();
 
comboBox1.DataSource = elements;
comboBox1.DisplayMember = "opis";
comboBox1.ValueMember = "wartosc";
bind to enum c#

Kod metody GetValueDescriptionEnumerable

Żeby to zadziałało, potrzebujemy prostej metody pomocniczej.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
 
namespace EnumDemo.Helpers
{
    public static class EnumHelper
    {
        public static IEnumerable<Tuple<T, string>> 
        GetValueDescriptionEnumerable<T>() where T : struct
        {
            if (!typeof(T).IsEnum) throw new InvalidOperationException();
            foreach (T item in Enum.GetValues(typeof(T)))
            {
                var fi = typeof(T).GetField(item.ToString());
                var attribute = fi
                     .GetCustomAttributes(typeof(DescriptionAttribute), false)
                     .FirstOrDefault( ) as DescriptionAttribute;
                var description = 
                    attribute == null ? 
                    item.ToString() : 
                    attribute.Description;         
                yield return new Tuple<T, string>(item, description);
            }
        }
    }
}

Zalety powyższej metody:

  • opis trzymamy zawsze blisko definicji enum
  • unikamy ręcznego mapowania wartość ↔ opis

Repozytorium kodu

Aplikacja demo powyższego rozwiązania znajduje się w repozytorium GitHub (opens new window).