¿Cómo vincular RadioButtons a una enumeración?

406

Tengo una enumeración como esta:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Tengo una propiedad en mi DataContext:

public MyLovelyEnum VeryLovelyEnum { get; set; }

Y obtuve tres RadioButtons en mi cliente WPF.

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

Ahora, ¿cómo enlazo los RadioButtons a la propiedad para un enlace bidireccional adecuado?

Sam
fuente
3
Si está buscando hacer esto sin especificar RadioButtons individuales en su XAML, recomendaría un ListBox vinculado a los valores de enumeración como este o esto , y que tiene la plantilla de elemento sobrescrita para usar RadioButtons como este .
Rachel

Respuestas:

389

Podrías usar un convertidor más genérico

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
}

Y en la XAML-Part usas:

<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
fuente
51
Funcionó como un encanto para mí. Como complemento, modifiqué ConvertBack para que también devuelva UnsetValue en "false", porque silverlight (y presumiblemente WPF apropiado) llama al convertidor dos veces, una vez al desactivar el valor del botón de radio anterior y nuevamente para configurar el nuevo. Estaba colgando otras cosas del instalador de propiedades, así que solo quería que se llamara una vez. - if (parameterString == null || value.Equals (false)) return DependencyProperty.UnsetValue;
MarcE
8
Por lo que puedo decir, esto debe hacerse a menos que los botones de radio estén en diferentes grupos (y los botones AFAIK sin GroupName establecidos que tienen el mismo padre están por defecto en el mismo grupo). De lo contrario, las llamadas para establecer la propiedad "rebotan" y dan como resultado un comportamiento extraño.
nlawalker
2
sí, pero si llama a Unset en el convertidor cuando se establece en false, entonces no es un verdadero EnumToBooleanConverter sino más bien un EnumToRadioButtonConverter. Por lo tanto, compruebo si el valor es diferente en mi configurador de propiedades: if (_myEnumBackingField == value) return;
Stéphane
8
El enlace en esta solución solo funciona correctamente en un sentido. No pude alternar programáticamente el botón de radio asignando la propiedad enlazada a un valor diferente. Si desea un funcionamiento adecuado y una mejor solución, use el enfoque de scott.
l46kok
2
@Marc, ¿no es lo correcto devolver en ese caso 'Binding.DoNothing' y no 'DependencyProperty.UnsetValue'?
Mark A. Donohoe
560

Puede simplificar aún más la respuesta aceptada. En lugar de escribir las enumeraciones como cadenas en xaml y hacer más trabajo en su convertidor de lo necesario, puede pasar explícitamente el valor de enumeración en lugar de una representación de cadena, y como CrimsonX comentó, los errores se generan en tiempo de compilación en lugar de tiempo de ejecución:

ConverterParameter = {x: Local estático: 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>

Luego simplifica el convertidor:

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

Editar (16 de diciembre de 2010):

Gracias a anon por sugerir devolver Binding.DoNothing en lugar de DependencyProperty.UnsetValue.


Nota - Varios grupos de RadioButtons en el mismo contenedor (17 de febrero de 2011):

En xaml, si los botones de opción comparten el mismo contenedor principal, al seleccionar uno se desmarcarán todos los demás dentro de ese contenedor (incluso si están vinculados a una propiedad diferente). Así que trate de mantener sus RadioButton que están vinculados a una propiedad común agrupados en su propio contenedor como un panel de pila. En los casos en que sus RadioButtons relacionados no puedan compartir un solo contenedor primario, configure la propiedad GroupName de cada RadioButton en un valor común para agruparlos lógicamente.


Editar (5 de abril de 2011):

Simplificado ConvertBack's if-else para usar un operador ternario.


Nota - Tipo de enumeración anidado en una clase (28 de abril de 2011):

Si su tipo de enumeración está anidado en una clase (en lugar de directamente en el espacio de nombres), puede usar la sintaxis '+' para acceder a la enumeración en XAML como se indica en una respuesta (no marcada) a la pregunta No se puede encontrar tipo de enumeración para referencia estática en WPF :

ConverterParameter = {x: Local estático: YourClass + YourNestedEnumType.Enum1}

Sin embargo, debido a este problema de Microsoft Connect , el diseñador en VS2010 ya no cargará la declaración "Type 'local:YourClass+YourNestedEnumType' was not found.", pero el proyecto se compila y ejecuta con éxito. Por supuesto, puede evitar este problema si puede mover su tipo de enumeración al espacio de nombres directamente.


Editar (27 de enero de 12):

Si usa banderas Enum, el convertidor sería el siguiente:

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

Editar (7 de mayo '15):

En el caso de una enumeración anulable (eso no se hace en la pregunta, pero puede ser necesario en algunos casos, por ejemplo, ORM devuelve nulo de DB o cuando tenga sentido que en la lógica del programa no se proporcione el valor), recuerde agregar una verificación nula inicial en el Método de conversión y devuelve el valor bool apropiado, que generalmente es falso (si no desea que se seleccione ningún botón de radio), como a continuación:

    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 de octubre de 18):

Se actualizó el ejemplo para eliminar la posibilidad de lanzar una NullReferenceException. IsCheckedes un tipo anulable, por lo que regresar Nullable<Boolean>parece una solución razonable.

Scott
fuente
26
Estoy de acuerdo, creo que esta es una mejor solución. Además, el uso de esta conversión hará que el proyecto se rompa en tiempo de compilación, no en tiempo de ejecución, si se cambian los valores de enumeración, lo cual es una gran ventaja.
CrimsonX
44
Esta es ciertamente una solución mucho mejor que la aceptada. +1
OrPaz
77
Buena solución Agregaría que esto es realmente solo un convertidor de comparación que compara 2 valores. Podría tener un nombre más genérico que EnumToBooleanConverter como ComparisonConverter
MikeKulls
55
@ Scott, muy bien. Este convertidor es bueno en cualquier caso, con o sin atributo Flags. Pero sería una tontería en la mayoría de los casos usar este filtro directamente como convertidor con enum como banderas. La razón es que debe alcanzar el cálculo booleano (| = o ^ =) con el valor anterior para obtener el resultado adecuado, pero el convertidor no tiene acceso al valor anterior. Luego debe agregar un valor booleano para cada valor de enumeración y hacer el cálculo booleano adecuado usted mismo en su modelo MVVM. Pero gracias por cada información, muy útil.
Eric Ouellet
2
En Windows Phone 8 (posiblemente en el caso de Win Store Apps) no tenemos x: static, por lo que no podemos usar la solución directamente aquí. Sin embargo, el IDE / Complier es lo suficientemente inteligente y busca la cadena en todos los literales de cadena (supongo que de todos modos). por ejemplo, esto funciona <RadioButton IsChecked = "{Binding TrackingMode, ConverterParameter = Driving, Converter = {StaticResource EnumToBooleanConverter}, Mode = TwoWay}" /> Cualquier error tipográfico en Driving se detectaría durante el tiempo de diseño / compilación en lugar del tiempo de ejecución.
Adarsha
26

Para la respuesta EnumToBooleanConverter: en lugar de devolver DependencyProperty.UnsetValue, considere devolver Binding.DoNothing para el caso en el que el valor del botón de radio IsChecked se convierte en falso. El primero indica un problema (y puede mostrar al usuario un rectángulo rojo o indicadores de validación similares) mientras que el segundo simplemente indica que no se debe hacer nada, que es lo que se desea en ese 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

luego
fuente
No hay enlace. Nada en Silverlight. Es solo WPF. Use nulo en su lugar.
Alexander Vasilyev
1
Encuadernación: nada ha desaparecido de UWP.
BlackICE
5

Usaría RadioButtons en un ListBox y luego me vincularía al SelectedValue

Este es un hilo antiguo sobre este tema, pero la idea base debería ser la misma: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

Martin Moser
fuente
Obtengo un enlace bidireccional haciendo un método similar usando ListBox y DataTemplate, por lo que debería.
Bryan Anderson el
3
Esta es, con mucho, la mejor solución, todo lo demás causa código redundante. ( Otro ejemplo de uso de un ListBox)
HB
3

Para UWP, no es tan simple: debe saltar a través de un aro adicional para pasar un valor de campo como parámetro.

Ejemplo 1

Válido tanto para WPF como para UWP.

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

Ejemplo 2

Válido tanto para WPF como para UWP.

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

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

Ejemplo 3

Válido solo para WPF!

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

UWP no es compatible, x:Staticpor lo que el Ejemplo 3 está fuera de discusión; suponiendo que vaya con el Ejemplo 1 , el resultado es un código más detallado. El ejemplo 2 es ligeramente mejor, pero aún no es ideal.

Solución

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

Luego, para cada tipo que desee admitir, defina un convertidor que incluya el tipo de enumeración.

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

La razón por la que debe encuadrarse es porque aparentemente no hay forma de hacer referencia al tipo en el ConvertBackmétodo; el boxeo se encarga de eso. Si sigue cualquiera de los dos primeros ejemplos, puede hacer referencia al tipo de parámetro, eliminando la necesidad de heredar de una clase en caja; Si desea hacerlo todo en una línea y con la menor verbosidad posible, la última solución es ideal.

El uso se asemeja al Ejemplo 2 , pero es, de hecho, menos detallado.

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

La desventaja es que debe definir un convertidor para cada tipo que desee admitir.

James M
fuente
1

He creado una nueva clase para manejar RadioButtons y CheckBoxes vinculantes para enumeraciones. Funciona para enumeraciones marcadas (con múltiples selecciones de casillas de verificación) y enumeraciones no marcadas para casillas de verificación de selección única o botones de opción. Tampoco requiere ningún ValueConverters en absoluto.

Esto puede parecer más complicado al principio, sin embargo, una vez que copie esta clase en su proyecto, ya está hecho. Es genérico, por lo que puede reutilizarse fácilmente para cualquier enumeración.

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

Y para saber cómo usarlo, supongamos que tiene una enumeración para ejecutar una tarea de forma manual o automática, y puede programarse para cualquier día de la semana, y algunas opciones opcionales ...

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
}

Ahora, aquí está lo fácil que es usar esta clase:

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

Y así de fácil es enlazar casillas de verificación y botones de opción con esta clase:

<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. Cuando se carga la IU, se seleccionará el botón de opción "Manual" y podrá modificar su selección entre "Manual" o "Automático", pero siempre se debe seleccionar cualquiera de ellos.
  2. Todos los días de la semana estarán desmarcados, pero cualquier número de ellos puede estar marcado o desmarcado.
  3. "Opción A" y "Opción B" estarán inicialmente desmarcadas. Puede marcar uno u otro, al marcar uno desmarcará el otro (similar a RadioButtons), pero ahora también puede desmarcar ambos (que no puede hacer con RadioButton de WPF, por eso se está usando CheckBox aquí)
Mella
fuente
Suponga que tiene 3 elementos en la enumeración de StartTask, como {Indefinido, Manual, Automático} Desea establecer Undefined de manera predeterminada porque hasta que un usuario establezca un valor, no está definido. Además: ¿Cómo se trata el SelectedItem? Su ViewModel no tiene SelectedStartTask.
user1040323
En mi ViewModel, la propiedad StartUp es un EnumSelection<StartTask>objeto. Si observa la definición de EnumSelection<T>puede ver que tiene una propiedad Value. Por lo tanto, el modelo de vista no necesita tener una "SelectedStartTask". Se podría utilizar StartUp.Value. Y en cuanto a tener un valor predeterminado de Indefinido, vea la 3ª enumeración, Opciones adicionales, tiene Ninguno en lugar de Indefinido, pero puede cambiar el nombre a lo que desee.
Nick
1

Esto también funciona para 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());
    }
}

Enlace de una sola enumeración a varias casillas de verificación.

Ali Bayat
fuente
1
Les digo un gran "GRACIAS" por el favor que me hicieron. Funcionó como un encanto para mí.
Elham Azadfar
0

Basado en el EnumToBooleanConverter de Scott. Noté que el método ConvertBack no funciona en Enum con código de banderas.

He intentado el siguiente código:

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 única cosa que no puedo ir a trabajar es hacer un molde a partir intde targetTypelo que lo hice codificada para NavigationProjectDates, la enumeración que yo uso. Y targetType == NavigationProjectDates...


Edite para obtener más convertidores genéricos de Flags Enum:

    clase pública FlagsEnumToBooleanConverter: IValueConverter {
        privado int _flags = 0;
        conversión de objeto público (valor de objeto, tipo targetType, parámetro de objeto, lenguaje de cadena) {
            if (valor == nulo) devuelve falso;
            _flags = (int) valor;
            Escriba t = value.GetType ();
            objeto o = Enum.ToObject (t, parámetro);
            return ((Enum) value). HasFlag ((Enum) o);
        }

        ConvertBack de objeto público (valor de objeto, tipo targetType, parámetro de objeto, lenguaje de cadena)
        {
            if (valor? .Equals (verdadero) ?? falso) {
                _flags = _flags | (int) parámetro;
            }
            más {
                _flags = _flags & ~ (int) parámetro;
            }
            return _flags;
        }
    }
KenGey
fuente
Alguien había editado mi respuesta para agregar el código Flags, así que, sinceramente, nunca lo intenté / usé yo mismo y consideré eliminarlo, ya que creo que tiene más sentido como su propia respuesta. Si puedo encontrar algo de tiempo más tarde, puedo intentar armar algo para probar ese código, así como lo que tienes y tal vez ayudarte a encontrar una mejor solución para tu problema.
Scott
0

Puede crear los botones de radio dinámicamente, ListBoxpuede ayudarlo a hacer eso, sin convertidores, bastante simple.

A continuación, se detallan los pasos detallados: cree un ListBox y establezca ItemsSource para el cuadro de lista como la enumeración MyLovelyEnumy enlace el SelectedItem del ListBox a la VeryLovelyEnumpropiedad. Luego se crearán los botones de radio para cada elemento ListBox.

  • Paso 1 : agregue la enumeración a los recursos estáticos para su ventana, UserControl o 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>
  • Paso 2 : use el cuadro de lista y Control Templatecomplete cada elemento dentro como botón de 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>

La ventaja es la siguiente: si algún día su clase de enumeración cambia, no necesita actualizar la GUI (archivo XAML).

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

Bravo Yeung
fuente