Comment lier RadioButtons à une énumération?

406

J'ai une énumération comme celle-ci:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

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

public MyLovelyEnum VeryLovelyEnum { get; set; }

Et j'ai obtenu trois RadioButtons dans mon client WPF.

<RadioButton Margin="3">First Selection</RadioButton>
<RadioButton Margin="3">The Other Selection</RadioButton>
<RadioButton Margin="3">Yet Another one</RadioButton>

Maintenant, comment lier les RadioButtons à la propriété pour une liaison bidirectionnelle appropriée?

Sam
la source
3
Si vous cherchez à le faire sans spécifier des RadioButtons individuels dans votre XAML, je recommanderais un ListBox lié aux valeurs d'énumération comme ceci ou cela , et qui a le modèle d'élément écrasé pour utiliser des RadioButtons comme celui-ci .
Rachel

Réponses:

389

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

Et dans la partie XAML que vous utilisez:

<Grid>
    <Grid.Resources>
      <l:EnumBooleanConverter x:Key="enumBooleanConverter" />
    </Grid.Resources>
    <StackPanel >
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=FirstSelection}">first selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=TheOtherSelection}">the other selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=YetAnotherOne}">yet another one</RadioButton>
    </StackPanel>
</Grid>
Lars
la source
51
A fonctionné à merveille pour moi. En complément, j'ai modifié ConvertBack pour retourner également UnsetValue sur "false", car silverlight (et probablement WPF proprement dit) appelle le convertisseur deux fois - une fois lors de la réinitialisation de l'ancienne valeur du bouton radio et de nouveau pour définir la nouvelle. J'étais en train de suspendre d'autres choses sur le setter de la propriété, donc je ne voulais l'appeler qu'une seule fois. - if (parameterString == null || value.Equals (false)) return DependencyProperty.UnsetValue;
MarcE
8
D'après ce que je peux dire, cela doit être fait sauf si les boutons radio sont dans des groupes différents (et les boutons AFAIK sans GroupName définis qui ont le même parent sont par défaut dans le même groupe). Sinon, les appels pour définir la propriété "rebondissent" et entraînent un comportement étrange.
nlawalker
2
oui mais si vous appelez Unset dans le convertisseur lors de la définition de false, ce n'est pas un vrai EnumToBooleanConverter mais plus un EnumToRadioButtonConverter. Donc, à la place, je vérifie si la valeur est différente dans mon setter de propriété: if (_myEnumBackingField == value) return;
Stéphane
8
La liaison sur cette solution ne fonctionne correctement que dans un sens. Je ne pouvais pas basculer par programmation le bouton radio en affectant la propriété liée à une valeur différente. Si vous voulez une solution de travail appropriée ET meilleure, utilisez l'approche de scott.
l46kok
2
@Marc, n'est-ce pas la bonne chose à renvoyer dans ce cas 'Binding.DoNothing' et non 'DependencyProperty.UnsetValue'?
Mark A. Donohoe
560

Vous pouvez encore simplifier la réponse acceptée. Au lieu de taper les énumérations sous forme de chaînes dans xaml et de faire plus de travail dans votre convertisseur que nécessaire, vous pouvez explicitement passer la valeur enum au lieu d'une représentation sous forme de chaîne, et comme l'a commenté CrimsonX, les erreurs sont générées au moment de la compilation plutôt qu'à l'exécution:

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

<StackPanel>
    <StackPanel.Resources>          
        <local:ComparisonConverter x:Key="ComparisonConverter" />          
    </StackPanel.Resources>
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum1}}" />
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum2}}" />
</StackPanel>

Simplifiez ensuite le convertisseur:

public class ComparisonConverter : 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) == true ? parameter : Binding.DoNothing;
    }
}

Modifier (16 décembre 10):

Merci à anon d'avoir suggéré de retourner Binding.DoNothing plutôt que DependencyProperty.UnsetValue.


Remarque - Plusieurs groupes de RadioButtons dans le même conteneur (17 février 2011):

Dans xaml, si les boutons radio partagent le même conteneur parent, la sélection d'un désélectionnera tous les autres contenus 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 pile. 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 logiquement.


Edit (5 avril 11):

If-else de ConvertBack simplifié pour utiliser un opérateur ternaire.


Remarque - Type d'énumération imbriqué dans une classe (28 avril 2011):

Si votre type d'énumération est imbriqué dans une classe (plutôt que directement dans l'espace de noms), vous pourrez peut-être utiliser la syntaxe '+' pour accéder à l'énumération en XAML comme indiqué dans une réponse (non marquée) à la question Impossible de trouver type enum pour référence statique dans WPF :

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

En raison de ce problème de connexion Microsoft , cependant, le concepteur dans VS2010 ne chargera plus la déclaration "Type 'local:YourClass+YourNestedEnumType' was not found.", mais le projet se compile et s'exécute correctement. Bien sûr, vous pouvez éviter ce problème si vous pouvez déplacer directement votre type d'énumération dans l'espace de noms.


Edit (27 janvier 12):

Si vous utilisez des drapeaux Enum, le convertisseur serait le suivant:

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'une énumération Nullable (ce qui n'est pas demandé dans la question, mais peut être nécessaire dans certains cas, par exemple, ORM renvoyant null à partir de la base de données ou chaque fois qu'il peut être logique que dans la logique du programme la valeur ne soit pas fournie), n'oubliez pas d'ajouter une vérification initiale nulle dans la méthode de conversion et renvoyer la valeur booléenne appropriée, qui est généralement fausse (si vous ne voulez pas de bouton radio 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);
    }

Remarque - NullReferenceException (10 octobre 2018):

Mise à jour de l'exemple pour supprimer la possibilité de lever une NullReferenceException. IsCheckedest un type nullable, donc le retour Nullable<Boolean>semble une solution raisonnable.

Scott
la source
26
Je suis d'accord, je pense que c'est une meilleure solution. En outre, l'utilisation de cette conversion entraînera la rupture du projet au moment de la compilation, et non au moment de l'exécution, si les valeurs d'énumération sont modifiées, ce qui est un gros avantage.
CrimsonX
4
C'est certainement une bien meilleure solution que celle acceptée. +1
OrPaz
7
Belle solution. J'ajouterais que c'est vraiment juste un convertisseur de comparaison comparant 2 valeurs. Il pourrait avoir un nom plus générique que EnumToBooleanConverter tel que ComparisonConverter
MikeKulls
5
@ Scott, très gentil. Ce convertisseur est bon dans tous les cas, avec ou sans attribut Flags. Mais il serait idiot dans la plupart des cas d'utiliser ce filtre directement comme convertisseur avec enum comme drapeaux. La raison en est que vous devez obtenir un calcul booléen (| = ou ^ =) avec la valeur précédente pour obtenir un résultat correct mais le convertisseur n'a pas accès à la valeur précédente. Vous devez ensuite ajouter un booléen pour chaque valeur d'énumération et effectuer le calcul booléen approprié vous-même dans votre modèle MVVM. Mais merci pour chaque info, très utile.
Eric Ouellet
2
Dans Windows Phone 8 (éventuellement dans le cas des applications Win Store), nous n'avons pas x: static, nous ne pouvons donc pas utiliser directement la solution ici. Cependant, l'IDE / Complier est suffisamment intelligent et recherche la chaîne par rapport à tous les littéraux de chaîne (je suppose de toute façon). Par exemple, cela fonctionne <RadioButton IsChecked = "{Binding TrackingMode, ConverterParameter = Driving, Converter = {StaticResource EnumToBooleanConverter}, Mode = TwoWay}" /> Toutes les fautes de frappe dans Driving seraient détectées pendant la conception / compilation plutôt que pendant l'exécution.
Adarsha
26

Pour la réponse EnumToBooleanConverter: Au lieu de renvoyer DependencyProperty.UnsetValue, envisagez de renvoyer Binding.DoNothing dans le cas où la valeur IsChecked du bouton radio devient fausse. Le premier indique un problème (et peut 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 souhaité 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

anon
la source
Il n'y a pas de lien, rien dans Silverlight. C'est seulement WPF. Utilisez plutôt null.
Alexander Vasilyev, du
1
Reliure.Rien n'a également disparu de l'UWP.
BlackICE
5

J'utiliserais les RadioButtons dans une ListBox, puis je me lierais à la SelectedValue.

Il s'agit d'un fil 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/

Martin Moser
la source
J'obtiens une liaison bidirectionnelle faisant une méthode similaire en utilisant un ListBox et un DataTemplate, donc vous devriez.
Bryan Anderson
Ce bug: geekswithblogs.net/claraoscura/archive/2008/10/17/125901.aspx a ruiné une journée pour moi.
Slampen
3
C'est de loin la meilleure solution, tout le reste provoque du code redondant. ( Un autre exemple d'utilisation d'une ListBox)
HB
3

Pour UWP, ce n'est pas si simple: vous devez sauter à travers un cercle supplémentaire pour passer une valeur de champ comme paramètre.

Exemple 1

Valable pour WPF et UWP.

<MyControl>
    <MyControl.MyProperty>
        <Binding Converter="{StaticResource EnumToBooleanConverter}" Path="AnotherProperty">
            <Binding.ConverterParameter>
                <MyLibrary:MyEnum>Field</MyLibrary:MyEnum>
            </Binding.ConverterParameter>
        </MyControl>
    </MyControl.MyProperty>
</MyControl>

Exemple 2

Valable pour WPF et UWP.

...
<MyLibrary:MyEnum x:Key="MyEnumField">Field</MyLibrary:MyEnum>
...

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={StaticResource MyEnumField}}"/>

Exemple 3

Valable uniquement pour WPF!

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static MyLibrary:MyEnum.Field}}"/>

UWP ne prend pas en charge, x:Staticdonc l' exemple 3 est hors de question; en supposant que vous allez avec l' exemple 1 , le résultat est un code plus détaillé. L'exemple 2 est légèrement meilleur, mais n'est toujours pas idéal.

Solution

public abstract class EnumToBooleanConverter<TEnum> : 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);
    }
}

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

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

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

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

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource MyEnumToBooleanConverter}, ConverterParameter=Field}"/>

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

James M
la source
1

J'ai créé une nouvelle classe pour gérer la liaison des RadioButtons et CheckBoxes aux énumérations. 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 également aucun convertisseur de valeur.

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

public class EnumSelection<T> : 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));
  }
}

Et pour savoir comment l'utiliser, disons que vous disposez d'une énumération pour exécuter une tâche manuellement ou automatiquement, et pouvez être planifiée pour n'importe quel jour 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 à quel point il est facile d'utiliser cette classe:

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

  public EnumSelection<StartTask> StartUp { get; private set; }
  public EnumSelection<DayOfWeek> Days { get; private set; }
  public EnumSelection<AdditionalOptions> Options { get; private set; }
}

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

<StackPanel Orientation="Vertical">
  <StackPanel Orientation="Horizontal">
    <!-- Using RadioButtons for exactly 1 selection behavior -->
    <RadioButton IsChecked="{Binding StartUp[Manual]}">Manual</RadioButton>
    <RadioButton IsChecked="{Binding StartUp[Automatic]}">Automatic</RadioButton>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <!-- Using CheckBoxes for 0 or Many selection behavior -->
    <CheckBox IsChecked="{Binding Days[Sunday]}">Sunday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Monday]}">Monday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Tuesday]}">Tuesday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Wednesday]}">Wednesday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Thursday]}">Thursday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Friday]}">Friday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Saturday]}">Saturday</CheckBox>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <!-- Using CheckBoxes for 0 or 1 selection behavior -->
    <CheckBox IsChecked="{Binding Options[OptionA]}">Option A</CheckBox>
    <CheckBox IsChecked="{Binding Options[OptionB]}">Option B</CheckBox>
  </StackPanel>
</StackPanel>
  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. Chaque jour de la semaine ne sera pas coché, mais n'importe quel nombre d'entre eux pourra être coché ou décoché.
  3. "Option A" et "Option B" seront toutes deux décochées initialement. Vous pouvez cocher l'un ou l'autre, cocher l'un désélectionnera l'autre (similaire à RadioButtons), mais maintenant vous pouvez également décocher les deux (ce que vous ne pouvez pas faire avec le RadioButton de WPF, c'est pourquoi CheckBox est utilisé ici)
pseudo
la source
Supposons que vous ayez 3 éléments dans l'énumération StartTask, tels que {Non défini, Manuel, Automatique}. Vous souhaitez définir par défaut Non défini car jusqu'à ce qu'un utilisateur définisse une valeur, il n'est pas défini. Aussi: Comment est traité le SelectedItem? Votre ViewModel n'a pas de SelectedStartTask.
user1040323
Dans mon ViewModel, la propriété StartUp est un EnumSelection<StartTask>objet. Si vous regardez la définition de EnumSelection<T>vous pouvez voir qu'elle a une propriété Value. Le modèle de vue n'a donc pas besoin d'avoir une "SelectedStartTask". Vous utiliseriez StartUp.Value. Et comme pour avoir une valeur par défaut de Undefined, voir la 3ème énumération, AdditionalOptions, il a un None au lieu d'un Undefined, mais vous pouvez changer le nom de celui-ci comme vous le souhaitez.
Nick
1

Cela fonctionne également 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.ToString());
    }
}

Lier une seule énumération à plusieurs cases à cocher.

Ali Bayat
la source
1
Je vous dis un grand "MERCI" pour la faveur que vous m'avez faite. Cela a fonctionné comme un charme pour moi.
Elham Azadfar
0

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 n'arrive pas à travailler est de faire un casting de intà targetTypedonc je l'ai fait en dur NavigationProjectDates, enum que j'utilise. Et targetType == NavigationProjectDates...


Modifier pour un convertisseur d'énumérations plus générique:

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

        objet public ConvertBack (valeur d'objet, type targetType, paramètre d'objet, langage de chaîne)
        {
            if (valeur? .Equals (true) ?? false) {
                _flags = _flags | paramètre (int);
            }
            autre {
                _flags = _flags & paramètre ~ (int);
            }
            return _flags;
        }
    }
KenGey
la source
Quelqu'un avait modifié ma réponse pour l'ajouter dans le code avec Flags, donc honnêtement, je ne l'ai jamais essayé / utilisé moi-même et j'avais envisagé de la supprimer car je pense que cela a plus de sens que sa propre réponse. Si je peux trouver un peu de temps plus tard, je peux essayer de mettre quelque chose ensemble pour tester ce code ainsi que ce que vous avez et peut-être aider à trouver une meilleure solution à votre problème.
Scott
0

Vous pouvez créer les boutons radio dynamiquement, ListBoxpeut vous aider à le faire, sans convertisseurs, assez simple.

Les étapes concrètes sont les suivantes: créer un ListBox et définir le ItemsSource pour la listbox comme énumération MyLovelyEnumet lier le SelectedItem du ListBox à la VeryLovelyEnumpropriété. Ensuite, les boutons radio pour chaque ListBoxItem seront créés.

  • Étape 1 : ajoutez l'énumération aux ressources statiques pour votre fenêtre, UserControl ou Grid, etc.
    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="{x:Type system:Enum}"
                            x:Key="MyLovelyEnum">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:MyLovelyEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
  • Étape 2 : Utilisez la zone de liste et Control Templatepour remplir chaque élément à l'intérieur en tant que bouton radio
    <ListBox ItemsSource="{Binding Source={StaticResource MyLovelyEnum}}" SelectedItem="{Binding VeryLovelyEnum, Mode=TwoWay}" >
        <ListBox.Resources>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <RadioButton
                                Content="{TemplateBinding ContentPresenter.Content}"
                                IsChecked="{Binding Path=IsSelected,
                                RelativeSource={RelativeSource TemplatedParent},
                                Mode=TwoWay}" />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
    </ListBox>

L' avantage est ci-dessous: si un jour votre classe enum change, vous n'avez pas besoin de mettre à jour l'interface graphique (fichier XAML).

Références: https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

Bravo Yeung
la source