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

Resuelto Sam asked hace 15 años • 11 respuestas

Tengo una enumeración como esta:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Obtuve una propiedad en mi DataContext:

public MyLovelyEnum VeryLovelyEnum { get; set; }

Y tengo 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 vinculo los RadioButtons a la propiedad para una vinculación bidireccional adecuada?

Sam avatar Dec 29 '08 18:12 Sam
Aceptado

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 comentó CrimsonX, los errores se generan en tiempo de compilación en lugar de tiempo de ejecución:

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>

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 anulará la selección de todos los demás dentro de ese contenedor (incluso si están vinculados a una propiedad diferente). Por lo tanto, intente mantener los RadioButton vinculados a una propiedad común agrupados en su propio contenedor, como un panel de pila. En los casos en los que sus RadioButtons relacionados no puedan compartir un único contenedor principal, establezca la propiedad GroupName de cada RadioButton en un valor común para agruparlos lógicamente.

Editar (5 de abril de 2011):

If-else de ConvertBack simplificado 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), es posible que pueda usar la sintaxis '+' para acceder a la enumeración en XAML como se indica en una respuesta (no marcada) a la pregunta:

ConverterParameter={x:Estático local: YourClass+ YourNestedEnumType.Enum1}

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


Editar (27 de enero de 2012):

Si usa indicadores 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 de 2015):

En el caso de una enumeración anulable (que **no** se pregunta en la pregunta, pero puede ser necesaria en algunos casos, por ejemplo, ORM que devuelve un valor nulo desde la base de datos 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 Convertir y devolver el valor bool apropiado, que generalmente es falso (si no desea seleccionar ningún botón de opción), como se muestra 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 2018):

Se actualizó el ejemplo para eliminar la posibilidad de generar una excepción NullReferenceException. `IsChecked` es un tipo que acepta valores NULL, por lo que devolver `Nullable` parece una solución razonable.
Scott avatar May 25 '2010 22:05 Scott

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 parte XAML 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 avatar Jan 02 '2009 13:01 Lars

Para la respuesta de EnumToBooleanConverter: en lugar de devolver DependencyProperty.UnsetValue, considere devolver Binding.DoNothing para el caso en el que el valor IsChecked del botón de opción se vuelva 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 .no hacer nada.aspx

anon avatar Sep 03 '2010 14:09 anon