Come associare RadioButtons a un enum?


406

Ho un enum come questo:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Ho ottenuto una proprietà nel mio DataContext:

public MyLovelyEnum VeryLovelyEnum { get; set; }

E ho ricevuto tre RadioButton nel mio client WPF.

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

Ora come posso associare i RadioButton alla proprietà per un corretto collegamento bidirezionale?


3
Se stai cercando di farlo senza specificare i singoli RadioButton nel tuo XAML, consiglierei un ListBox associato ai valori enum come questo o questo , e che ha il modello di elemento sovrascritto per usare i RadioButton in questo modo .
Rachel,

Risposte:


389

È possibile utilizzare 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:

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

51
Ha funzionato benissimo per me. Come aggiunta ho modificato ConvertBack per restituire anche UnsetValue su "false", perché silverlight (e presumibilmente WPF proprio) chiama il convertitore due volte, una volta quando si disattiva il vecchio valore del pulsante di opzione e di nuovo per impostare quello nuovo. Stavo appendendo altre cose al setter della proprietà, quindi volevo che fosse chiamato solo una volta. - if (parameterString == null || value.Equals (false)) restituisce DependencyProperty.UnsetValue;
Marc

8
Da quello che posso dire, questo deve essere fatto a meno che i pulsanti di opzione non siano in gruppi diversi (e i pulsanti AFAIK senza gruppo GroupName che hanno lo stesso genitore sono di default nello stesso gruppo). Altrimenti, le chiamate per impostare la proprietà "rimbalzo" e comportano comportamenti strani.
nlawalker,

2
sì, ma se si chiama Unset nel convertitore quando si imposta su false, allora non è un vero EnumToBooleanConverter ma più un EnumToRadioButtonConverter. Quindi, invece, controllo se il valore è diverso nel mio setter proprietà: if (_myEnumBackingField == value) return;
Stéphane,

8
L'associazione a questa soluzione funziona correttamente solo a senso unico. Non è stato possibile impostare a livello di codice il pulsante di opzione assegnando la proprietà associata a un valore diverso. Se vuoi una soluzione funzionante E migliore, usa l'approccio di scott.
Bangkok,

2
@Marc, in quel caso non è la cosa giusta da restituire "Binding.DoNothing" e non "DependencyProperty.UnsetValue"?
Mark A. Donohoe,

560

Puoi semplificare ulteriormente la risposta accettata. Invece di scrivere gli enum come stringhe in xaml e fare più lavoro nel convertitore del necessario, puoi esplicitamente passare il valore enum invece di una rappresentazione di stringa e, come ha commentato CrimsonX, gli errori vengono generati al momento della compilazione piuttosto che in fase di esecuzione:

ConverterParameter = {x: Static local: 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>

Quindi semplifica il convertitore:

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

Modifica (16 dic '10):

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


Nota - Più gruppi di pulsanti radio nello stesso contenitore (17 febbraio 11):

In xaml, se i pulsanti di opzione condividono lo stesso contenitore principale, 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 raggruppata nel loro contenitore come un pannello di stack. Nei casi in cui i RadioButton correlati non possono condividere un singolo contenitore principale, impostare la proprietà GroupName di ciascun RadioButton su un valore comune per raggrupparli logicamente.


Modifica (5 aprile 11):

If-else di ConvertBack semplificato per l'utilizzo di un operatore ternario.


Nota: tipo Enum nidificato in una classe (28 aprile 11):

Se il tipo di enum è nidificato in una classe (anziché direttamente nello spazio dei nomi), potresti essere in grado di utilizzare la sintassi '+' per accedere all'enum in XAML come indicato in una risposta (non contrassegnata) alla domanda Impossibile trovare tipo enum per riferimento statico in WPF :

ConverterParameter = {x: Static local: YourClass + YourNestedEnumType.Enum1}

A causa di questo problema di Microsoft Connect , tuttavia, il progettista in VS2010 non caricherà più la dichiarazione "Type 'local:YourClass+YourNestedEnumType' was not found.", ma il progetto viene compilato ed eseguito correttamente. Ovviamente, puoi evitare questo problema se sei in grado di spostare direttamente il tuo tipo enum nello spazio dei nomi.


Modifica (27 gennaio 12):

Se si utilizzano flag Enum, il convertitore sarebbe 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 Enumullabile nullable (che non è richiesto nella domanda, ma può essere necessario in alcuni casi, ad esempio ORM che restituisce null dal DB o ogni volta che 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);
    }

Nota - NullReferenceException (10 ottobre 18):

Aggiornato l'esempio per rimuovere la possibilità di lanciare una NullReferenceException. IsCheckedè un tipo nullable quindi il ritorno Nullable<Boolean>sembra una soluzione ragionevole.


26
Sono d'accordo, credo che questa sia una soluzione migliore. Inoltre, l'utilizzo di questa conversione causerà l'interruzione del progetto in fase di compilazione, non in fase di esecuzione, se i valori di enumerazione vengono modificati, il che rappresenta un grande vantaggio.
CrimsonX,

4
Questa è sicuramente una soluzione molto migliore di quella accettata. +1
OrPaz,

7
Bella soluzione. Vorrei aggiungere che questo è davvero solo un convertitore di confronto che confronta 2 valori. Potrebbe avere un nome più generico di EnumToBooleanConverter come ComparisonConverter
MikeKulls

5
@ Scott, molto gentile. Questo convertitore è buono in ogni caso, con o senza l'attributo Flags. Ma nella maggior parte dei casi sarebbe sciocco usare questo filtro direttamente come convertitore con enum come bandiere. Il motivo è che dovresti ottenere calc booleani (| = o ^ =) con il valore precedente per ottenere il risultato corretto ma il convertitore non ha accesso al valore precedente. È quindi necessario aggiungere un valore booleano per ciascun valore enum ed eseguire il calcolo booleano corretto nel modello MVVM. Ma grazie per ogni informazione, molto utile.
Eric Ouellet,

2
In Windows Phone 8 (possibilmente nel caso di Win Store Apps) non abbiamo x: static, quindi non possiamo usare direttamente la soluzione qui. Tuttavia, l'IDE / Complier è abbastanza intelligente e cerca la stringa rispetto a tutti i letterali di stringa (la mia ipotesi comunque). ad esempio, funziona <RadioButton IsChecked = "{Binding TrackingMode, ConverterParameter = Driving, Converter = {StaticResource EnumToBooleanConverter}, Mode = TwoWay}" /> Eventuali errori di battitura in Driving verrebbero rilevati durante la fase di progettazione / compilazione anziché durante il runtime.
Adarsha,

26

Per la risposta EnumToBooleanConverter: Invece di restituire DependencyProperty.UnsetValue prendere in considerazione 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 il secondo indica semplicemente che non si dovrebbe fare nulla, che è ciò che si desidera 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


Non c'è nessun legame. Niente in Silverlight. È solo WPF. Usa invece null.
Alexander Vasilyev,

1
Binding.Nulla è passato anche da UWP.
BlackICE,

5

Vorrei utilizzare i RadioButtons in un ListBox e quindi associare a 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/


Ottengo un'associazione a due vie facendo un metodo simile usando ListBox e DataTemplate, quindi dovresti.
Bryan Anderson,


3
Questa è di gran lunga la soluzione migliore, tutto il resto causa codice ridondante. ( Un altro esempio di utilizzo di un ListBox)
HB

3

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

Esempio 1

Valido per WPF e UWP.

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

Esempio 2

Valido per WPF e UWP.

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

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

Esempio 3

Valido solo per WPF!

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

UWP non supporta x:Staticquindi l' esempio 3 è fuori discussione; supponendo di andare con l' esempio 1 , il risultato è un codice più dettagliato. L'esempio 2 è leggermente migliore, ma comunque non ideale.

Soluzione

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

Quindi, per ogni tipo che desideri supportare, definisci un convertitore che contenga il tipo enum.

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

Il motivo per cui deve essere inscatolato è perché apparentemente non c'è modo di fare riferimento al tipo nel ConvertBackmetodo; la boxe se ne occupa. Se vai con uno dei primi due esempi, puoi semplicemente fare riferimento al tipo di parametro, eliminando la necessità di ereditare da una classe in box; se desideri fare tutto in una riga e con la minima verbosità possibile, quest'ultima soluzione è l'ideale.

L'utilizzo assomiglia all'esempio 2 , ma in realtà è meno dettagliato.

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

Il rovescio della medaglia è che è necessario definire un convertitore per ogni tipo che si desidera supportare.


1

Ho creato una nuova classe per gestire RadioButtons e CheckBoxes per enumerare. Funziona con enumerazioni contrassegnate (con selezioni multiple di caselle di controllo) ed enumerazioni non contrassegnate per caselle di controllo a selezione singola o pulsanti di opzione. Inoltre non richiede alcun ValueConverters.

All'inizio questo potrebbe sembrare più complicato, tuttavia, una volta copiata questa classe nel tuo progetto, è fatta. È generico, quindi può essere facilmente riutilizzato per qualsiasi enum.

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

E per come usarlo, supponiamo che tu abbia un enum per l'esecuzione di un'attività manualmente o automaticamente e che possa essere programmato per tutti i giorni 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 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; }
}

Ed ecco quanto è facile associare caselle di controllo e pulsanti di opzione con questa 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. Quando l'interfaccia utente viene caricata, verrà selezionato il pulsante di opzione "Manuale" ed è possibile modificare la selezione tra "Manuale" o "Automatico", ma uno dei due deve essere sempre selezionato.
  2. Ogni giorno della settimana sarà deselezionato, ma qualsiasi numero di essi potrà essere controllato o deselezionato.
  3. "Opzione A" e "Opzione B" saranno entrambi inizialmente deselezionati. Puoi controllare l'uno o l'altro, controllando l'uno deselezionerai l'altro (simile a RadioButtons), ma ora puoi anche deselezionare entrambi (cosa che non puoi fare con RadioButton di WPF, motivo per cui CheckBox viene usato qui)

Supponiamo di avere 3 elementi nell'enumerazione StartTask come {Non definito, Manuale, Automatico} Si desidera impostare come predefinito Non definito perché fino a quando un utente imposta un valore non è definito. Inoltre: come viene gestito SelectedItem? ViewModel non ha SelectedStartTask.
user1040323

Nel mio ViewModel, la proprietà StartUp è un EnumSelection<StartTask>oggetto. Se guardi la definizione di EnumSelection<T>puoi vedere che ha una proprietà Value. Pertanto, il modello di visualizzazione non deve avere un "SelectedStartTask". Useresti StartUp.Value. E per quanto riguarda il valore predefinito di Undefined, vedi il terzo enum, AdditionalOptions, ha un None anziché un Undefined, ma puoi cambiarne il nome con quello che vuoi.
Nick,

1

Questo funziona 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());
    }
}

Associare un singolo enum a più caselle di controllo.


1
Dico un grande "GRAZIE" a te per il favore che hai fatto per me. Ha funzionato come un incanto per me.
Elham Azadfar,

0

Basato sul convertitore EnumToBoolean di Scott. Ho notato che il metodo ConvertBack non funziona su Enum con il codice flags.

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 posso andare al lavoro è quello di fare un cast da inta targetTypecosì ho fatto hardcoded per NavigationProjectDatesl'enum che uso. E targetType == NavigationProjectDates...


Modifica per un convertitore Enum Flags più generico:

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

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

Qualcuno aveva modificato la mia risposta per aggiungerla con il codice Flags, quindi onestamente, non l'ho mai provato / usato da solo e avevo considerato di rimuoverlo perché penso che abbia più senso come risposta propria. Se riesco a trovare un po 'di tempo dopo, posso provare a mettere insieme qualcosa per testare quel codice così come quello che hai e forse aiutare a trovare una soluzione migliore per il tuo problema.
Scott,

0

È possibile creare i pulsanti di opzione in modo dinamico, ListBoxpuò aiutarti a farlo, senza convertitori, abbastanza semplice.

I passaggi concreati sono i seguenti: creare un ListBox e impostare ItemsSource per la listbox come enum MyLovelyEnume associare SelectedItem di ListBox alla VeryLovelyEnumproprietà. Quindi verranno creati i pulsanti di opzione per ciascun ListBoxItem.

  • Passaggio 1 : aggiungi l'enum alle risorse statiche per Window, UserControl o Grid ecc.
    <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>
  • Passaggio 2 : utilizzare la casella di riepilogo e Control Templatepopolare ogni elemento all'interno come pulsante di opzione
    <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>

Il vantaggio è sotto: se un giorno la tua classe enum cambia, non è necessario aggiornare la GUI (file XAML).

Riferimenti: https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.