Come bind i RadioButton a un enum?

Ho un enume come questo:

public enum MyLovelyEnum { FirstSelection, TheOtherSelection, YetAnotherOne }; 

Ho ottenuto una proprietà nel mio DataContext:

 public MyLovelyEnum VeryLovelyEnum { get; set; } 

E ho ottenuto tre RadioButton nel mio client WPF.

 First Selection The Other Selection Yet Another one 

Ora, come posso bind i RadioButton alla proprietà per un corretto collegamento a due vie?

Potresti usare un convertitore più generico

 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; if (Enum.IsDefined(value.GetType(), value) == false) return DependencyProperty.UnsetValue; object parameterValue = Enum.Parse(value.GetType(), parameterString); return parameterValue.Equals(value); } 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 } 

E nella parte XAML usi:

      first selection the other selection yet another one   

È ansible semplificare ulteriormente la risposta accettata. Invece di digitare enum come stringhe in xaml e fare più lavoro nel tuo convertitore del necessario, puoi passare esplicitamente il valore enum invece di una rappresentazione stringa e, come commentato CrimsonX, gli errori vengono lanciati in fase di compilazione piuttosto che in runtime:

ConverterParameter = {x: Statico locale: YourEnumType.Enum1}

        

Quindi semplificare il convertitore:

 public class EnumToBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value.Equals(parameter); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value.Equals(true) ? parameter : Binding.DoNothing; } } 

Nota: gruppi multipli di RadioButton nello stesso container (17 febbraio 11):

In xaml, se i pulsanti di opzione condividono lo stesso contenitore padre, quindi selezionarne uno deselezionerà tutti gli altri all’interno di quel contenitore (anche se sono associati a una proprietà diversa). Quindi cerca di mantenere i tuoi RadioButton associati a una proprietà comune raggruppati insieme nel proprio contenitore come un pannello di stack. Nei casi in cui i RadioButton correlati non possono condividere un singolo contenitore padre, impostare la proprietà GroupName di ciascun RadioButton su un valore comune per raggrupparli logicamente.

Nota – Tipo Enum nidificato in una class (28 aprile 11):

Se il tuo tipo di enum è annidato in una class (piuttosto che direttamente nello spazio dei nomi), potresti essere in grado di utilizzare la syntax ‘+’ per accedere all’enumerazione in XAML come indicato in una risposta (non contrassegnata) alla domanda Imansible trovare tipo enum per riferimento statico in WPF :

ConverterParameter = {x: Statico locale: YourClass + YourNestedEnumType.Enum1}

A causa di questo problema Microsoft Connect , tuttavia, il designer in VS2010 non caricherà più "Type 'local:YourClass+YourNestedEnumType' was not found." , ma il progetto viene compilato ed eseguito correttamente. Naturalmente, è ansible evitare questo problema se si è in grado di spostare direttamente il tipo di enum nello spazio dei nomi.

Modifica (16 dicembre 10):

Grazie ad anon per aver suggerito di restituire Binding.DoNothing piuttosto che DependencyProperty.UnsetValue.

Modifica (5 aprile 11):

Semplificato ConvertBack’s if-else per utilizzare un operatore ternario.

Modifica (27 gennaio 12):

Se si utilizzano i flag Enum, il convertitore sarà il seguente:

 public class EnumToBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return ((Enum)value).HasFlag((Enum)parameter); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value.Equals(true) ? parameter : Binding.DoNothing; } } 

Modifica (7 maggio 15):

Nel caso di un Enum Nullable (che non viene richiesto nella domanda, ma può essere necessario in alcuni casi, ad esempio, ORM restituisce null dal DB o ogni qualvolta potrebbe avere senso che nella logica del programma il valore non sia fornito), ricordarsi di aggiungere un controllo Null iniziale nel Metodo di conversione e restituisce il valore bool appropriato, che in genere è falso (se non si desidera selezionare alcun pulsante di opzione), come di seguito:

  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) { return false; // or return parameter.Equals(YourEnumType.SomeDefaultValue); } return value.Equals(parameter); } 

Per la risposta EnumToBooleanConverter: invece di restituire DependencyProperty.UnsetValue, considerare la restituzione di Binding.DoNothing per il caso in cui il valore IsChecked del pulsante di opzione diventa falso. Il primo indica un problema (e potrebbe mostrare all’utente un rettangolo rosso o indicatori di convalida simili) mentre quest’ultimo indica solo che non si dovrebbe fare nulla, che è ciò che si vuole in quel caso.

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback.aspx http://msdn.microsoft.com/en-us/library/system.windows.data.binding .donothing.aspx

Vorrei usare i RadioButton in un ListBox e quindi associarmi al SelectedValue.

Questa è una discussione precedente su questo argomento, ma l’idea di base dovrebbe essere la stessa: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

Per UWP, non è così semplice: devi passare attraverso un cerchio aggiuntivo per passare un valore di campo come parametro.

Esempio 1

Valido per WPF e UWP.

     Field     

Esempio 2

Valido per WPF e UWP.

 ... Field ...  

Esempio 3

Valido solo per WPF!

  

UWP non supporta x:Static quindi l’ esempio 3 è fuori questione; partendo dall’esempio 1 , il risultato è un codice più dettagliato. L’esempio 2 è leggermente migliore, ma non ancora ideale.

Soluzione

 public abstract class EnumToBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { var Parameter = parameter as string; if (Parameter == null) return DependencyProperty.UnsetValue; if (Enum.IsDefined(typeof(TEnum), value) == false) return DependencyProperty.UnsetValue; return Enum.Parse(typeof(TEnum), Parameter).Equals(value); } public object ConvertBack(object value, Type targetType, object parameter, string language) { var Parameter = parameter as string; return Parameter == null ? DependencyProperty.UnsetValue : Enum.Parse(typeof(TEnum), Parameter); } } 

Quindi, per ciascun tipo che desideri supportare, definisci un convertitore che contiene il tipo di enum.

 public class MyEnumToBooleanConverter : EnumToBooleanConverter { //Nothing to do! } 

Il motivo per cui deve essere inserito in una scatola è perché non c’è apparentemente alcun modo per fare riferimento al tipo nel metodo ConvertBack ; il pugilato si prende cura di questo. Se si utilizza uno dei primi due esempi, è sufficiente fare riferimento al tipo di parametro, eliminando la necessità di ereditare da una class in box; se vuoi fare tutto in una sola riga e con meno verbosità ansible, quest’ultima soluzione è l’ideale.

L’utilizzo è simile all’esempio 2 , ma in realtà è meno dettagliato.

  

Lo svantaggio è che devi definire un convertitore per ogni tipo che desideri supportare.

Questo lavoro anche per Checkbox .

 public class EnumToBoolConverter:IValueConverter { private int val; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { int intParam = (int)parameter; val = (int)value; return ((intParam & val) != 0); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { val ^= (int)parameter; return Enum.Parse(targetType, val.ToString()); } } 

Associazione di una singola enumerazione a più checkbox.

Estese le grandi idee di cui sopra con la possibilità di associare i pulsanti di opzione a qualsiasi tipo (enumerazione, booleana, stringa, numero intero, ecc.) E forniva qui codice di esempio funzionante:

http://www.codeproject.com/Tips/720497/Binding-Radio-Buttons-to-a-Single-Property

Ho creato una nuova class per gestire i RadioButton e i CheckBox vincolanti alle enumerazioni. Funziona per enumerazioni contrassegnate (con selezioni multiple di caselle di controllo) e enumerazioni non contrassegnate per caselle di selezione o pulsanti di selezione a selezione singola. Inoltre non richiede affatto ValueConverters.

Questo potrebbe sembrare più complicato all’inizio, tuttavia, una volta copiata questa class nel tuo progetto, è fatta. È generico quindi può essere facilmente riutilizzato per qualsiasi enum.

 public class EnumSelection : INotifyPropertyChanged where T : struct, IComparable, IFormattable, IConvertible { private T value; // stored value of the Enum private bool isFlagged; // Enum uses flags? private bool canDeselect; // Can be deselected? (Radio buttons cannot deselect, checkboxes can) private T blankValue; // what is considered the "blank" value if it can be deselected? public EnumSelection(T value) : this(value, false, default(T)) { } public EnumSelection(T value, bool canDeselect) : this(value, canDeselect, default(T)) { } public EnumSelection(T value, T blankValue) : this(value, true, blankValue) { } public EnumSelection(T value, bool canDeselect, T blankValue) { if (!typeof(T).IsEnum) throw new ArgumentException($"{nameof(T)} must be an enum type"); // I really wish there was a way to constrain generic types to enums... isFlagged = typeof(T).IsDefined(typeof(FlagsAttribute), false); this.value = value; this.canDeselect = canDeselect; this.blankValue = blankValue; } public T Value { get { return value; } set { if (this.value.Equals(value)) return; this.value = value; OnPropertyChanged(); OnPropertyChanged("Item[]"); // Notify that the indexer property has changed } } [IndexerName("Item")] public bool this[T key] { get { int iKey = (int)(object)key; return isFlagged ? ((int)(object)value & iKey) == iKey : value.Equals(key); } set { if (isFlagged) { int iValue = (int)(object)this.value; int iKey = (int)(object)key; if (((iValue & iKey) == iKey) == value) return; if (value) Value = (T)(object)(iValue | iKey); else Value = (T)(object)(iValue & ~iKey); } else { if (this.value.Equals(key) == value) return; if (!value && !canDeselect) return; Value = value ? key : blankValue; } } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

E per come usarlo, diciamo che hai un enum per eseguire un’attività manualmente o automaticamente, e può essere programmato per qualsiasi giorno della settimana, e alcune opzioni opzionali …

 public enum StartTask { Manual, Automatic } [Flags()] public enum DayOfWeek { Sunday = 1 << 0, Monday = 1 << 1, Tuesday = 1 << 2, Wednesday = 1 << 3, Thursday = 1 << 4, Friday = 1 << 5, Saturday = 1 << 6 } public enum AdditionalOptions { None = 0, OptionA, OptionB } 

Ora, ecco come è facile usare questa class:

 public class MyViewModel : ViewModelBase { public MyViewModel() { StartUp = new EnumSelection(StartTask.Manual); Days = new EnumSelection(default(DayOfWeek)); Options = new EnumSelection(AdditionalOptions.None, true, AdditionalOptions.None); } public EnumSelection StartUp { get; private set; } public EnumSelection Days { get; private set; } public EnumSelection Options { get; private set; } } 

Ed ecco come è facile associare checkbox e pulsanti di opzione con questa class:

    Manual Automatic    Sunday Monday Tuesday Wednesday Thursday Friday Saturday    Option A Option B   
  1. Quando l'interfaccia utente viene caricata, verrà selezionato il pulsante di opzione "Manuale" e sarà ansible modificare la selezione tra "Manuale" o "Automatico" ma uno di essi deve essere sempre selezionato.
  2. Ogni giorno della settimana sarà deselezionato, ma qualsiasi numero di essi può essere selezionato o deselezionato.
  3. "L'opzione A" e "l'opzione B" saranno entrambe inizialmente deselezionate. Puoi controllare l'uno o l'altro, controllarne uno deselezionerà l'altro (simile a RadioButton), ma ora puoi anche deselezionarli entrambi (cosa che non puoi fare con RadioButton di WPF, motivo per cui CheckBox viene usato qui)

Basato sull’EnumToBooleanConverter di Scott. Ho notato che il metodo ConvertBack non funziona su Enum con codice flag.

Ho provato il seguente codice:

 public class EnumHasFlagToBooleanConverter : IValueConverter { private object _obj; public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { _obj = value; return ((Enum)value).HasFlag((Enum)parameter); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value.Equals(true)) { if (((Enum)_obj).HasFlag((Enum)parameter)) { // Do nothing return Binding.DoNothing; } else { int i = (int)_obj; int ii = (int)parameter; int newInt = i+ii; return (NavigationProjectDates)newInt; } } else { if (((Enum)_obj).HasFlag((Enum)parameter)) { int i = (int)_obj; int ii = (int)parameter; int newInt = i-ii; return (NavigationProjectDates)newInt; } else { // do nothing return Binding.DoNothing; } } } } 

L’unica cosa che non riesco a far funzionare è di fare un cast da int a targetType quindi l’ho reso codificato in NavigationProjectDates , l’enum che uso. E, targetType == NavigationProjectDates


Modifica per più generico convertitore Flags Enum:

     public class FlagsEnumToBooleanConverter: IValueConverter {
         int privato _flags = 0;
         object pubblico Convert (valore object, tipo targetType, parametro object, linguaggio stringa) {
             if (value == null) restituisce false;
             _flags = (int) valore;
             Digitare t = value.GetType ();
             object o = Enum.ToObject (t, parametro);
             return ((Enum) value) .HasFlag ((Enum) o);
         }

         object pubblico ConvertBack (valore dell'object, tipo targetType, parametro object, linguaggio stringa)
         {
             if (value? .Equals (true) ?? false) {
                 _flags = _flags |  (int) parametro;
             }
             altro {
                 _flags = _flags & ~ (int) parametro;
             }
             return _flags;
         }
     }