Is it possible to create a generic Int-to-Enum Converter?

匿名 (未验证) 提交于 2019-12-03 02:24:01

问题:

I'd like to be able to say

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

and to have it resolve as True if the int value is equal to (int)MyEnum.Value

I know I could make a Converter that returns (MyEnum)intValue, however then I'd have to make a converter for every Enum type I use in my DataTriggers.

Is there a generic way to create a converter that would give me this kind of functionality?

回答1:

It is possible to create a converter between enum values and their underlying integral types in a reusable way -- that is, you don't need to define a new converter for each enum types. There's enough information provided to Convert and ConvertBack for this.

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

When invoked, this converter flips the value's type between int/enum value based purely on the value and targetType values. There are no hard-coded enum types.



回答2:

I think I figured it out

I just needed to set my ConverterParameter instead of the Value equal to the Enum I am looking for, and evaluate for True/False

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

Converter

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


回答3:

You could also go the other way around and convert the enum to int for the Value using a custom Markup Extension.

Example

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


回答4:

We've wanted to do this a few times in the past as well, so we built several extension methods (on int, long, etc) to help us out. The core of all of these is implemented in a single static generic TryAsEnum method:

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

This implementation handles Enums with any underlying type, as well as enums defined with the [Flags] attribute.



回答5:

You could do a ToString() on the int value and then pass that into the static Enum.Parse or Enum.TryParse method which takes the enum type you care about and returns the appropriate value.

This isn't a perfect solution though because it won't work with integers that represent the binary ORing of multiple enum values



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!