Simple WPF RadioButton Binding?

Quelle est la manière la plus simple de lier un groupe de 3 boutons radio à une propriété de type int pour les valeurs 1, 2 ou 3?

En fait, en utilisant le convertisseur comme celui-ci, la liaison bidirectionnelle est interrompue, et comme je l’ai dit plus haut, vous ne pouvez pas non plus l’utiliser avec des énumérations. La meilleure façon de faire est d’utiliser un style simple contre un ListBox, comme ceci:

Remarque: contrairement à ce que DrWPF.com a indiqué dans son exemple, ne placez pas ContentPresenter dans RadioButton ou si vous ajoutez un élément avec un contenu tel qu’un bouton ou autre chose, vous ne pourrez pas définir ou interagir avec lui . Cette technique résout ce problème. En outre, vous devez gérer le gris du texte et supprimer les marges sur les étiquettes, sinon il ne sera pas rendu correctement. Ce style traite à la fois pour vous.

                    

Vous avez maintenant l’apparence des boutons radio, mais vous pouvez effectuer une liaison bidirectionnelle et utiliser une énumération. Voici comment…

  Some option Some other option Yet another option  

De plus, puisque nous avons séparé explicitement le style qui traget le ListBoxItem plutôt que de le mettre en ligne, comme le montrent les autres exemples, vous pouvez désormais en créer un nouveau pour personnaliser des éléments tels que l’espacement. (Cela ne fonctionnera pas si vous essayez simplement de cibler ListBoxItem car le style de clé remplace les cibles de contrôle génériques.)

Voici un exemple de mettre une marge de 6 au-dessus et au-dessous de chaque élément. (Notez comment vous devez explicitement appliquer le style via la propriété ItemContainerStyle et ne pas simplement cibler ListBoxItem dans la section des ressources de ListBox pour la raison indiquée ci-dessus.)

     Some option Some other option Ter another option  

Je suis venu avec une solution simple.

J’ai une classe model.cs avec:

 private int _isSuccess; public int IsSuccess { get { return _isSuccess; } set { _isSuccess = value; } } 

J’ai le fichier Window1.xaml.cs avec DataContext défini sur model.cs. Le xaml contient les boutons radio:

    

Voici mon convertisseur:

 public class RadioBoolToIntConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { int integer = (int)value; if (integer==int.Parse(parameter.ToSsortingng())) return true; else return false; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return parameter; } } 

Et bien sûr, dans les ressources de Window1:

    

Je suis très surpris que personne ne soit arrivé avec ce type de solution pour le lier à la liste bool. Ce n’est peut-être pas le plus propre, mais il peut être utilisé très facilement:

 private bool[] _modeArray = new bool[] { true, false, false}; public bool[] ModeArray { get { return _modeArray ; } } public int SelectedMode { get { return Array.IndexOf(_modeArray, true); } } 

en XAML:

    

NOTE: vous n’avez pas besoin d’une liaison bidirectionnelle si vous ne voulez pas en vérifier une par défaut. La liaison TwoWay est le plus gros inconvénient de cette solution.

Avantages:

  • Pas besoin de code derrière
  • Pas besoin de classe supplémentaire (IValue Converter)
  • Pas besoin d’enumération supplémentaire
  • ne nécessite pas de liaison bizzare
  • simple et facile à comprendre
  • ne viole pas MVVM (heh, au moins je l’espère)

Je sais que la solution est très en retard, mais j’ai une solution alternative, plus légère et plus simple. Dérivez une classe de System.Windows.Controls.RadioButton et déclarez deux propriétés de dépendance RadioValue et RadioBinding . Ensuite, dans le code de la classe, remplacez OnChecked et définissez la valeur de la propriété RadioBinding sur celle de la valeur de la propriété RadioValue . Dans l’autre sens, RadioBinding les modifications apscopes à la propriété RadioBinding aide d’un rappel et, si la nouvelle valeur est égale à la valeur de la propriété RadioValue , définissez sa propriété IsChecked sur true .

Voici le code:

 public class MyRadioButton : RadioButton { public object RadioValue { get { return (object)GetValue(RadioValueProperty); } set { SetValue(RadioValueProperty, value); } } // Using a DependencyProperty as the backing store for RadioValue. This enables animation, styling, binding, etc... public static readonly DependencyProperty RadioValueProperty = DependencyProperty.Register( "RadioValue", typeof(object), typeof(MyRadioButton), new UIPropertyMetadata(null)); public object RadioBinding { get { return (object)GetValue(RadioBindingProperty); } set { SetValue(RadioBindingProperty, value); } } // Using a DependencyProperty as the backing store for RadioBinding. This enables animation, styling, binding, etc... public static readonly DependencyProperty RadioBindingProperty = DependencyProperty.Register( "RadioBinding", typeof(object), typeof(MyRadioButton), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRadioBindingChanged)); private static void OnRadioBindingChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { MyRadioButton rb = (MyRadioButton)d; if (rb.RadioValue.Equals(e.NewValue)) rb.SetCurrentValue(RadioButton.IsCheckedProperty, true); } protected override void OnChecked(RoutedEventArgs e) { base.OnChecked(e); SetCurrentValue(RadioBindingProperty, RadioValue); } } 

Utilisation de XAML:

     

J’espère que quelqu’un trouvera cela utile après tout ce temps 🙂

Parfois, il est possible de le résoudre dans le modèle comme ceci: Supposons que vous ayez 3 propriétés booléennes OptionA, OptionB, OptionC.

XAML:

    

CODE:

 private bool _optionA; public bool OptionA { get { return _optionA; } set { _optionA = value; if( _optionA ) { this.OptionB= false; this.OptionC = false; } } } private bool _optionB; public bool OptionB { get { return _optionB; } set { _optionB = value; if( _optionB ) { this.OptionA= false; this.OptionC = false; } } } private bool _optionC; public bool OptionC { get { return _optionC; } set { _optionC = value; if( _optionC ) { this.OptionA= false; this.OptionB = false; } } } 

Vous avez eu l’idée. Pas la chose la plus propre, mais facile.

Cet exemple peut sembler un peu long, mais son intention devrait être assez claire.

Il utilise 3 propriétés booléennes dans ViewModel appelé FlagForValue1 , FlagForValue2 et FlagForValue3 . Chacune de ces 3 propriétés est soutenue par un seul champ privé appelé _intValue .

Les 3 boutons Radio de la vue (xaml) sont chacun liés à la propriété Flag correspondante dans le modèle de vue. Cela signifie que le bouton radio affichant “Valeur 1” est lié à la propriété FlagForValue1 du modèle de vue et aux deux autres en conséquence.

Lorsque vous définissez l’une des propriétés dans le modèle de vue (par exemple FlagForValue1 ), il est important de générer également des événements de propriété modifiée pour les deux autres propriétés (par exemple FlagForValue2 et FlagForValue3 ) afin que l’interface utilisateur (infrastructure WPF INotifyPropertyChanged ) correctement.

  private int _intValue; public bool FlagForValue1 { get { return (_intValue == 1) ? true : false; } set { _intValue = 1; RaisePropertyChanged("FlagForValue1"); RaisePropertyChanged("FlagForValue2"); RaisePropertyChanged("FlagForValue3"); } } public bool FlagForValue2 { get { return (_intValue == 2) ? true : false; } set { _intValue = 2; RaisePropertyChanged("FlagForValue1"); RaisePropertyChanged("FlagForValue2"); RaisePropertyChanged("FlagForValue3"); } } public bool FlagForValue3 { get { return (_intValue == 3) ? true : false; } set { _intValue = 3; RaisePropertyChanged("FlagForValue1"); RaisePropertyChanged("FlagForValue2"); RaisePropertyChanged("FlagForValue3"); } } 

Le xaml ressemble à ceci:

  Value 1 Value 2 Value 3 

Je suis venu avec une solution en utilisant Binding.DoNothing retourné par le convertisseur qui ne rompt pas la liaison bidirectionnelle.

 public class EnumToCheckedConverter : IValueConverter { public Type Type { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && value.GetType() == Type) { try { var parameterFlag = Enum.Parse(Type, parameter as ssortingng); if (Equals(parameterFlag, value)) { return true; } } catch (ArgumentNullException) { return false; } catch (ArgumentException) { throw new NotSupportedException(); } return false; } else if (value == null) { return false; } throw new NotSupportedException(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && value is bool check) { if (check) { try { return Enum.Parse(Type, parameter as ssortingng); } catch(ArgumentNullException) { return Binding.DoNothing; } catch(ArgumentException) { return Binding.DoNothing; } } return Binding.DoNothing; } throw new NotSupportedException(); } } 

Usage:

  

Liaisons de boutons radio:

 Function