Comment lier RadioButtons à un enum?

J’ai un enum comme ça:

public enum MyLovelyEnum { FirstSelection, TheOtherSelection, YetAnotherOne }; 

J’ai une propriété dans mon DataContext:

 public MyLovelyEnum VeryLovelyEnum { get; set; } 

Et j’ai trois RadioButtons dans mon client WPF.

 First Selection The Other Selection Yet Another one 

Comment puis-je lier les RadioButtons à la propriété pour une liaison bidirectionnelle correcte?

Vous pourriez utiliser un convertisseur plus générique

 public class EnumBooleanConverter : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ssortingng parameterSsortingng = parameter as ssortingng; if (parameterSsortingng == null) return DependencyProperty.UnsetValue; if (Enum.IsDefined(value.GetType(), value) == false) return DependencyProperty.UnsetValue; object parameterValue = Enum.Parse(value.GetType(), parameterSsortingng); return parameterValue.Equals(value); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ssortingng parameterSsortingng = parameter as ssortingng; if (parameterSsortingng == null) return DependencyProperty.UnsetValue; return Enum.Parse(targetType, parameterSsortingng); } #endregion } 

Et dans la partie XAML, vous utilisez:

      first selection the other selection yet another one   

Vous pouvez simplifier davantage la réponse acceptée. Au lieu de taper les énumérations en tant que chaînes dans xaml et de faire plus de travail que nécessaire dans votre convertisseur, vous pouvez explicitement transmettre la valeur enum au lieu d’une représentation sous forme de chaîne.

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

        

Puis simplifiez le convertisseur:

 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; } } 

Remarque – Plusieurs groupes de boutons radio dans le même conteneur (17 février 11):

Dans xaml, si les boutons radio partagent le même conteneur parent, la sélection de l’un d’eux désélectionnera tous les autres dans ce conteneur (même s’ils sont liés à une propriété différente). Essayez donc de garder vos RadioButton liés à une propriété commune regroupés dans leur propre conteneur, comme un panneau de stack. Dans les cas où vos RadioButtons associés ne peuvent pas partager un seul conteneur parent, définissez la propriété GroupName de chaque RadioButton sur une valeur commune pour les regrouper de manière logique.

Remarque – Type Enum nested dans une classe (28 avril 2011):

Si votre type enum est nested dans une classe (plutôt que directement dans l’espace de noms), vous pouvez utiliser la syntaxe ‘+’ pour accéder à l’énumération dans XAML comme indiqué dans une réponse (non marquée) à la question Impossible de trouver type enum pour la référence statique dans WPF :

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

En raison de ce problème de Microsoft Connect , le concepteur de VS2010 ne sera plus chargé en indiquant "Type 'local:YourClass+YourNestedEnumType' was not found." , mais le projet comstack et s’exécute correctement. Bien sûr, vous pouvez éviter ce problème si vous pouvez déplacer votre type enum directement dans l’espace de noms.

Edit (16 décembre 10):

Merci à anon pour avoir suggéré de renvoyer Binding.DoNothing plutôt que DependencyProperty.UnsetValue.

Modifier (5 avril 11):

Convertisseur simplifié si, sinon, utiliser un opérateur ternaire.

Modifier (27 janvier 12):

Si vous utilisez des indicateurs Enum, le convertisseur sera comme suit:

 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; } } 

Edit (7 mai 15):

Dans le cas d’un Enum Nullable (qui n’est pas demandé dans la question, mais qui peut être nécessaire dans certains cas, par exemple ORM renvoyant null à DB ou chaque fois que cela peut sembler logique dans la logique du programme), n’oubliez pas d’append un contrôle initial nul dans la méthode de conversion et retourne la valeur bool appropriée, qui est généralement fausse (si vous ne souhaitez pas qu’un bouton radio soit sélectionné), comme ci-dessous:

  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); } 

Pour la réponse EnumToBooleanConverter: Au lieu de retourner DependencyProperty.UnsetValue, envisagez de renvoyer Binding.DoNothing pour le cas où la valeur du bouton radio IsChecked devient false. Le premier indique un problème (et pourrait montrer à l’utilisateur un rectangle rouge ou des indicateurs de validation similaires) tandis que le second indique simplement que rien ne doit être fait, ce qui est le cas dans ce cas.

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

Je voudrais utiliser les RadioButtons dans un ListBox, puis lier à SelectedValue.

Il s’agit d’un sujet plus ancien sur ce sujet, mais l’idée de base doit être la même: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

Pour UWP, ce n’est pas si simple: vous devez passer par un cercle supplémentaire pour passer une valeur de champ en tant que paramètre.

Exemple 1

Valable pour WPF et UWP.

     Field     

Exemple 2

Valable pour WPF et UWP.

 ... Field ...  

Exemple 3

Valable uniquement pour WPF!

  

UWP ne supporte pas x:Static donc l’ exemple 3 est hors de question; en supposant que vous allez avec l’ exemple 1 , le résultat est un code plus prolixe. L’exemple 2 est légèrement meilleur, mais toujours pas idéal.

Solution

 public abstract class EnumToBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, ssortingng language) { var Parameter = parameter as ssortingng; 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, ssortingng language) { var Parameter = parameter as ssortingng; return Parameter == null ? DependencyProperty.UnsetValue : Enum.Parse(typeof(TEnum), Parameter); } } 

Ensuite, pour chaque type que vous souhaitez prendre en charge, définissez un convertisseur qui contient le type enum.

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

La raison pour laquelle il doit être encadré est qu’il n’y a apparemment aucun moyen de faire référence au type dans la méthode ConvertBack ; la boxe s’en occupe. Si vous utilisez l’un des deux premiers exemples, vous pouvez simplement référencer le type de paramètre, en éliminant le besoin d’hériter d’une classe encadrée. Si vous voulez tout faire en une seule ligne et avec le moins de verbosité possible, la dernière solution est idéale.

L’utilisation ressemble à l’ exemple 2 , mais est en fait moins verbeuse.

  

L’inconvénient est que vous devez définir un convertisseur pour chaque type que vous souhaitez prendre en charge.

Cela fonctionne aussi pour 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.ToSsortingng()); } } 

Lier un seul enum à plusieurs cases à cocher.

Étendu les bonnes idées ci-dessus avec la possibilité de lier des boutons radio à n’importe quel type (énumération, booléen, chaîne, entier, etc.) et fourni un exemple de code de travail ici:

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

J’ai créé une nouvelle classe pour gérer les liaisons RadioButtons et CheckBoxes enums. Il fonctionne pour les énumérations marquées (avec plusieurs sélections de cases à cocher) et les énumérations non marquées pour les cases à cocher à sélection unique ou les boutons radio. Il ne nécessite pas non plus de ValueConverters.

Cela peut sembler plus compliqué au début, cependant, une fois que vous copiez cette classe dans votre projet, c’est fait. C’est générique donc il peut facilement être réutilisé pour n’importe quelle énumération.

 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(FlagsAtsortingbute), 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] ssortingng propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

Et pour savoir comment l’utiliser, supposons que vous ayez un enum pour exécuter une tâche manuellement ou automatiquement, et que vous pouvez la programmer pour tous les jours de la semaine, et certaines options facultatives …

 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 } 

Maintenant, voici comment il est facile d'utiliser cette classe:

 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; } } 

Et voici comment il est facile de lier des cases à cocher et des boutons radio avec cette classe:

    Manual Automatic    Sunday Monday Tuesday Wednesday Thursday Friday Saturday    Option A Option B   
  1. Lorsque l'interface utilisateur se charge, le bouton radio "Manuel" est sélectionné et vous pouvez modifier votre sélection entre "Manuel" ou "Automatique", mais l'un ou l'autre doit toujours être sélectionné.
  2. Tous les jours de la semaine ne seront pas cochés, mais vous pouvez les cocher ou les désélectionner.
  3. "Option A" et "Option B" seront toutes les deux non cochées. Vous pouvez vérifier l'un ou l'autre, en cochant que l'un décochera l'autre (similaire à RadioButtons), mais maintenant vous pouvez également les décocher (ce que vous ne pouvez pas faire avec RadioButton de WPF, c'est pourquoi CheckBox est utilisé ici)

Basé sur le EnumToBooleanConverter de Scott. J’ai remarqué que la méthode ConvertBack ne fonctionne pas sur le code Enum with flags.

J’ai essayé le code suivant:

 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; } } } } 

La seule chose que je ne parviens pas à faire est de faire un targetType d’ targetType en targetType donc je l’ai codé en dur sur NavigationProjectDates , l’énumère que j’utilise. Et, targetType == NavigationProjectDates


Modifier pour un convertisseur Flags Enum plus générique:

     classe publique FlagsEnumToBooleanConverter: IValueConverter {
         private int _flags = 0;
         object public Convertir (valeur d'object, type targetType, paramètre d'object, langage de chaîne) {
             if (value == null) renvoie false;
             _flags = (int) value;
             Tapez t = value.GetType ();
             object o = Enum.ToObject (t, paramètre);
             return ((Enum) value) .HasFlag ((Enum) o);
         }

         object public ConvertBack (valeur d'object, type targetType, paramètre d'object, langage de chaîne)
         {
             if (value? .Equals (true) ?? false) {
                 _flags = _flags |  paramètre (int);
             }
             autre {
                 _flags = _flags & ~ (int) paramètre;
             }
             retourne _flags;
         }
     }