2011-08-18 13 views
8

me gustaría poder decir¿Es posible crear un convertidor Int-to-Enum genérico?

<DataTrigger Binding="{Binding SomeIntValue}" 
      Value="{x:Static local:MyEnum.SomeValue}"> 

y tener que resolver como True si el valor es igual a int(int)MyEnum.Value

Sé que podría hacer una Converter que devuelve (MyEnum)intValue, sin embargo, a continuación, Tendría que hacer un convertidor para cada tipo de Enum que uso en mis DataTriggers.

¿Existe alguna forma genérica de crear un convertidor que me brinde este tipo de funcionalidad?

Respuesta

4

Creo que lo he descubierto

Sólo tenía que poner mi ConverterParameter en lugar de la Value igual a la enumeración Busco, y evaluar de Verdadero/Falso

<DataTrigger Value="True" 
      Binding="{Binding SomeIntValue, 
       Converter={StaticResource IsIntEqualEnumConverter}, 
       ConverterParameter={x:Static local:MyEnum.SomeValue}}"> 

convertidor

public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
{ 
    if (parameter == null || value == null) return false; 

    if (parameter.GetType().IsEnum && value is int) 
    { 
     return (int)parameter == (int)value; 
    } 
    return false; 
} 
0

Usted podría hacer un ToString() en el valor int y luego pasar que en el Enum.Parse estática o método Enum.TryParse que toma el tipo de enumeración se preocupa por y devuelve el valor apropiado.

Esto no es una solución perfecta, ya que aunque no va a trabajar con números enteros que representan la operación OR binaria de enumeración múltiples valores

+0

¿Cómo obtendré el Enum Type dentro del 'Convertidor'? – Rachel

3

También puede ir al revés y convertir la enumeración a int para el valor usando una extensión de marcado personalizada.

Ejemplo

<DataTrigger Binding="{Binding Path=MyNumber}" 
      Value="{Markup:EnumToInt {x:Static Visibility.Visible}}"> 

EnumToIntExtension

public class EnumToIntExtension : MarkupExtension 
{ 
    public object EnumValue 
    { 
     get; 
     set; 
    } 
    public EnumToIntExtension(object enumValue) 
    { 
     this.EnumValue = enumValue; 
    } 
    public override object ProvideValue(IServiceProvider provider) 
    { 
     if (EnumValue != null && EnumValue is Enum) 
     { 
      return System.Convert.ToInt32(EnumValue); 
     } 
     return -1; 
    } 
} 
+0

Nunca antes me he encontrado con MarkupExtensions, ¡gracias! Todavía estoy aprendiendo algo nuevo todos los días :) – Rachel

+0

Mismo aquí en realidad, recién comencé a usarlos y pueden ser muy útiles :) –

1

hemos querido hacer esto un par de veces en el pasado, así, por lo que hemos construido varios métodos de extensión (en int, long, etc.) para ayudarnos. El núcleo de todos ellos se implementa en un único método TryAsEnum genérico estática:

/// <summary> 
    /// Helper method to try to convert a value to an enumeration value. 
    /// 
    /// If <paramref name="value"/> is not convertable to <typeparam name="TEnum"/>, an exception will be thrown 
    /// as documented by Convert.ChangeType. 
    /// </summary> 
    /// <param name="value">The value to convert to the enumeration type.</param> 
    /// <param name="outEnum">The enumeration type value.</param> 
    /// <returns>true if value was successfully converted; false otherwise.</returns> 
    /// <exception cref="InvalidOperationException">Thrown if <typeparamref name="TEnum"/> is not an enum type. (Because we can't specify a generic constraint that T is an Enum.)</exception> 
    public static bool TryAsEnum<TValue, TEnum>(TValue value, out TEnum outEnum) where TEnum : struct 
    { 
     var enumType = typeof(TEnum); 

     if (!enumType.IsEnum) 
     { 
      throw new InvalidOperationException(string.Format("{0} is not an enum type.", enumType.Name)); 
     } 

     var valueAsUnderlyingType = Convert.ChangeType(value, Enum.GetUnderlyingType(enumType)); 

     if (Enum.IsDefined(enumType, valueAsUnderlyingType)) 
     { 
      outEnum = (TEnum) Enum.ToObject(enumType, valueAsUnderlyingType); 
      return true; 
     } 

     // IsDefined returns false if the value is multiple composed flags, so detect and handle that case 

     if(enumType.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any()) 
     { 
      // Flags attribute set on the enum. Get the enum value. 
      var enumValue = (TEnum)Enum.ToObject(enumType, valueAsUnderlyingType); 

      // If a value outside the actual enum range is set, then ToString will result in a numeric representation (rather than a string one). 
      // So if a number CANNOT be parsed from the ToString result, we know that only defined values have been set. 
      decimal parseResult; 
      if(!decimal.TryParse(enumValue.ToString(), out parseResult)) 
      { 
       outEnum = enumValue; 
       return true; 
      } 
     } 

     outEnum = default(TEnum); 
     return false; 
    } 

Esta implementación maneja Enums con cualquier tipo subyacente, así como enumeraciones definidas con el atributo [Banderas].

6

Es posible crear un convertidor entre los valores enum y sus tipos integrales subyacentes de forma reutilizable, es decir, no es necesario definir un nuevo convertidor para cada tipo de enumeración. Se proporciona suficiente información a Convert y ConvertBack para esto.

public sealed class BidirectionalEnumAndNumberConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value == null) 
      return null; 

     if (targetType.IsEnum) 
     { 
      // convert int to enum 
      return Enum.ToObject(targetType, value); 
     } 

     if (value.GetType().IsEnum) 
     { 
      // convert enum to int 
      return System.Convert.ChangeType(
       value, 
       Enum.GetUnderlyingType(value.GetType())); 
     } 

     return null; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     // perform the same conversion in both directions 
     return Convert(value, targetType, parameter, culture); 
    } 
} 

Cuando se invoca, este convertidor voltea el tipo del valor entre el valor/enum int basado puramente en los valores value y targetType. No hay tipos de enum codificados.

Cuestiones relacionadas