.NET Enumeration Types & WPF

U prethodnom postu smo se bavili osnovama enuma u C# .NET okruženju. Za efektnu prezentaciju najzahvalnije je napraviti primer koji ima dopadljiv korisnički interfejs, rešio sam da zakačim naše enume na WPF formu. Za ovu akciju je bilo potrebno malo više truda nego što sam se u prvi mah nadao, ali sam sasvim zadovoljan postignutim, što bi rekli ameri: „No pain, no gain“.

Ideja

Želimo da zakačimo (bind) vrednost enuma na grupu chekbox-ova koji omogućavaju prikaz i ažuriranje vrednosti na elegantan način. Enumom smo definisali dane u nedelji, a naša promenljiva predstavlja dane kojima se održava sastanak razvojnog tima. Pa da definišemo naš enum (Enum.cs):

   [Flags]
   public enum Days : byte
   {
      None = 0x0,
      Sunday = 0x1,
      Monday = 0x2,
      Tuesday = 0x4,
      Wednesday = 0x8,
      Thursday = 0x10,
      Friday = 0x20,
      Saturday = 0x40,
      WorkingDays = Monday | Tuesday | Wednesday | Thursday | Friday,
      All = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
   }

Wpf Binding

Najkraće, Windows Presentation Foundation (WPF) data binding omogućava jednostavan i dosledan mehanizam za interakciju korisnika sa podacima. Školski rečeno, uspostavlja vezu između prezentacionog i domenskog sloja aplikacije.

Da se vratimo našem enumu. Napravio sam WPF projekat iz Visual Studio 2010, definisao enum u fajlu Enum.cs. Dalje, pravimo našu Data klasu koja će sadržati property tipa Days, neka se zove MyData (MyData.cs), u njoj imamo private fild (polje?) meetingDays i public property (svojstvo?) MeetingDays, naravno oba tipa Days. Želimo i da naša klasa može da obavesti klijenta kada promeni vrednost, tako da ćemo da implementiramo INotifyPropertyChanged interfejs. Sve što treba da uradimo je da deklarišemo event tipa PropertyChangedEventHandler, naravno i da ga pozovemo kada do same promene dođe. Dodao sam i readonly property Meeting days koji vraća numeričku vrednost našeg enuma, da bi mogli da pratimo šta se dešava ispod haube, dok na interfejsu menjamo izabranu vrednost.

using System.ComponentModel;

namespace WpfApplication1
{
   public class MyData : INotifyPropertyChanged
   {
      private Days meetingDays;

      public Days MeetingDays
      {
         get { return meetingDays; }
         set
         {
          switch (value)
          {
           case Days.None:
           case Days.WorkingDays:
           case Days.All:
              meetingDays = value;
              break;
           default:
              meetingDays ^= value;
              break;
          }

          if (null != this.PropertyChanged)
          {
            PropertyChanged(this, new PropertyChangedEventArgs("MeetingDays"));
            PropertyChanged(this, new PropertyChangedEventArgs("MeetingDaysValue"));
          }
        }
      }

      public byte MeetingDaysValue { get { return (byte)meetingDays; } }

      #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
      #endregion
   }
}

Primetićete da setovanje vrednosti propertija MeetingDays nije jednostavna dodela vrednosti, već kada je vrednost dan onda radimo isključivo ili sa postojećom vrednošću, a ukoliko biramo neku od grupnih vrednosti, onda jednostavno dodeljujemo vrednost. Meni se čini da je ovakav način setovanja vrednosti najlogičniji.

WPF Forma

Sada instancu naše klase MyData dodelimo DataContext-u forme i bajndujemo na kontrole za prikaz. Za prikaz koristimo CheckBox-ove bindovane na property MeetingDays našeg DataContext-a. Avaj, CheckBox-ovi su napravljeni da rade sa boolean vrednostima, tako da se ne snalaze sa našim enumom, šta sad? Rešenje je jednostavno, treba nam Converter koji će prevoditi naše enum vrednosti u boolean-ove. Pravimo klasu koja implementira interfejs IvalueConverter i radi konverziju koja nam je potrebna:

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

namespace WpfApplication1
{
   public class EnumBooleanConverter : IValueConverter
   {
      #region IValueConverter Members
      public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      {
       string parameterString = parameter as string;

       if (parameterString == null)
        return DependencyProperty.UnsetValue;

       Days parameterValue = (Days) Enum.Parse(typeof(Days), parameterString);

       bool isSet;
       Days myDays = ((Days)value);

       if (parameterValue == Days.None)
        isSet = (myDays == Days.None);
       else
        isSet = myDays.HasFlag(parameterValue);

       return isSet;
      }

      public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
      {
       string parameterString = parameter as string;
       if (parameterString == null)
          return DependencyProperty.UnsetValue;

       return Enum.Parse(targetType, parameterString);
      }
      #endregion
   }
}

Primetite da Convert pored vrednosti i njenog tipa, prihvata i još jedan parametar, tako da ćemo moći da kažemo našoj kontroli koju vrednost enuma predstavlja, tj. prikazuje. Naravno ovo postoji mogućnost i da se lokalizuju ove vrednosti, čime se nisam bavio. Evo kako će sad izgledati naš XAML za jednu kontrolu:


Monday

To je to, sada možemo da završimo našu formu, koja na kraju izgleda ovako:

BindToEnumeration Screenshot

Kompletan source code je dostupan za download, možete slobodno da koristite i menjate primere, pod licencom Creative Commons 3.0, što podrazumeva da navodite originalni izvor, tj. da linkujete na ovaj blog i mene kao autora. Da bi otvorili projekat potrebano je da imate instaliran Visual Studio 2010, besplatnu express verziju možete skinuti sa ove adrese.

Pages:

Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>