Enumy są fajne. Chociaż dałoby się bez nich żyć, to ułatwiają naprawdę wiele rzeczy. Sęk w tym, że przyjąłem sobie za cel pisanie nazw metod, klas etc. w kodzie tylko i wyłącznie po angielsku, a interfejs na chwilę obecną tworzę w naszym pięknym języku. Jak zatem wyświetlić dla określonej wartości enuma przetłumaczoną (lub kompletnie inną) nazwę w widoku? Niby mamy atrybut [Display(Name = “DisplayName”)], ale … w tym przypadku nie zadziała.
Zacznijmy od początku (dla niecierpliwych umieszczę nagłówek Rozwiązanie, w miejscu kiedy skończę przynudzać i przejdę do konkretów). Każde zamówienie złożone w sklepie czy restauracji ma jakiś status. Może być złożone, zaakceptowane, wysłane i tak dalej. Statusy te mają wąską i raczej niezmienną pulę, więc postanowiłem wykorzystać enum, który dzięki przypisywaniu wartości liczbowej poszczególnym wartościom, będzie bardzo użyteczny jeszcze w inny sposób (ale o tym innym razem). Zastanowiłem się nad tym jakie statusy powinno mieć zamówienie w restauracji i wyszło mi coś takiego:
1 2 3 4 5 6 7 8 |
public enum OrderStatus { Ordered, Accepted, Sent, Done, Cancelled } |
W innych branżach sprzedaży online sprawa byłaby nieco bardziej skomplikowana, ale kluczem w dostawie jedzenia jest szybkość. Musi być więc ono złożone, zaakceptowane przez obsługę, wysłane i zakończone, w ostateczności z jakiegoś powodu możemy je anulować. Bardzo ważne w tym wypadku jest to, aby statusy były umieszczone w takiej kolejności, w jakiej przetwarzane jest zamówienie z opcjonalnymi statusami (najmniej prawdopodobne Cancelled) na samym końcu. Dlaczego? W najbliższym czasie opowiem Wam jak będą przetwarzane zamówienia i wtedy właśnie ujawni się powód, dla którego wybrałem ten konkretny sposób reprezentacji statusu zamówienia.
Jednak w momencie umieszczenia statusu w widoku w formie order.Status, wyświetlana jest przypisana wartość enuma. Niby mógłbym go wypełnić polskimi nazwami, ale wyglądałoby to moim zdaniem bardzo nieelegancko, więc postanowiłem sprawdzić czy atrybut Display, będzie w mojej sytuacji podobny, skoro załatwia podobne problemy w innych miejscach. W ten sposób mój enum zmienił się na następujący:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public enum OrderStatus { [Display(Name = "Złożone")] Ordered, [Display(Name = "Zaakceptowane")] Accepted, [Display(Name = "Wysłane")] Sent, [Display(Name = "Zakończone")] Done, [Display(Name = "Anulowane")] Cancelled } |
Z kolei samo wywołanie w widoku musiałem zamienić na Html.DisplayFor(o => o.Status). Niestety w widoku z listą zamówień dalej były one Accepted i Ordered, a tego właśnie starałem się uniknąć. Wystarczyła chwila grzebania w internetach (bo i problem nie jest jakoś szczególnie trudny), by znaleźć kilka różnych rozwiązań. Ja zdecydowałem się na takie.
Rozwiązanie
Do projektu wystarczy dodać metodę rozszerzającą enum.
1 2 3 4 |
public static string GetDisplayName(this Enum value) { return value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DisplayAttribute>().Name; } |
Wszystko co ona robi, to zwrócenie stringa z pola Name atrybutu Display. Jako, że atrybuty miałem już przypisane i był to ostatni kawałek układanki, to wystarczyło zmienić sposób wywołania w widoku na order.Status.GetDisplayName() i wszystkie statusy zostały wyświetlone piękną polszczyzną.
PS. Postanowiłem zacząć się socjalizować i założyłem fanpage tego bloga. Zapraszam na: https://www.facebook.com/hryniewskinet/