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";
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).