C# 是否可以创建通用的Int-to-Enum转换器?

C# 是否可以创建通用的Int-to-Enum转换器?,c#,wpf,enums,converter,datatrigger,C#,Wpf,Enums,Converter,Datatrigger,我想说 <DataTrigger Binding="{Binding SomeIntValue}" Value="{x:Static local:MyEnum.SomeValue}"> 如果int值等于(int)MyEnum.value 我知道我可以制作一个返回(MyEnum)intValue的转换器,但是我必须为我在DataTriggers中使用的每个枚举类型制作一个转换器 有没有一种通用的方法可以创建一个转换器来提供这种功能?您可以对int值执行

我想说

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

如果
int
值等于
(int)MyEnum.value

我知道我可以制作一个返回
(MyEnum)intValue
转换器
,但是我必须为我在DataTriggers中使用的每个枚举类型制作一个转换器

有没有一种通用的方法可以创建一个转换器来提供这种功能?

您可以对int值执行ToString(),然后将其传递到静态Enum.Parse或Enum.TryParse方法,该方法采用您关心的枚举类型并返回适当的值


但这不是一个完美的解决方案,因为它不适用于表示多个枚举值的二进制ORing的整数

我只需要将我的
ConverterParameter
而不是
设置为等于我要查找的枚举,并计算真/假

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

您也可以反过来使用自定义标记扩展将值的枚举转换为int

范例

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

过去我们也曾多次希望这样做,因此我们构建了几个扩展方法(基于int、long等)来帮助我们解决问题。所有这些的核心都在一个静态通用TryAsEnum方法中实现:

    /// <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;
    }
//
///方法尝试将值转换为枚举值。
/// 
///如果不可转换为,将引发异常
///如Convert.ChangeType所述。
/// 
///要转换为枚举类型的值。
///枚举类型值。
///如果值已成功转换,则为true;否则就错了。
///如果不是枚举类型,则引发。(因为我们不能指定t是枚举的泛型约束。)
公共静态bool TryAsEnum(TValue值,out-TEnum-outEnum),其中TEnum:struct
{
var enumType=typeof(TEnum);
如果(!enumType.IsEnum)
{
抛出新的InvalidOperationException(string.Format(“{0}不是枚举类型。”,enumType.Name));
}
var valueAsUnderlyingType=Convert.ChangeType(值,Enum.GetUnderlyingType(enumType));
if(已定义枚举(枚举类型,值为UnderlyingType))
{
outEnum=(TEnum)Enum.ToObject(enumType,valueAsUnderlyingType);
返回true;
}
//如果值是多个组合标志,IsDefined返回false,因此检测并处理该情况
if(enumType.GetCustomAttributes(typeof(FlagsAttribute),inherit:true).Any())
{
//在枚举上设置的标志属性。获取枚举值。
var enumValue=(TEnum)Enum.ToObject(enumType,valueAsUnderlyingType);
//如果设置了实际枚举范围之外的值,则ToString将导致数值表示(而不是字符串表示)。
//因此,如果无法从ToString结果中解析数字,我们知道只设置了定义的值。
十进制解析结果;
if(!decimal.TryParse(enumValue.ToString(),out parseResult))
{
outEnum=枚举值;
返回true;
}
}
outEnum=默认值(十纳姆);
返回false;
}

此实现处理任何基础类型的枚举,以及使用[Flags]属性定义的枚举。

可以以可重用的方式在枚举值及其基础整数类型之间创建转换器,也就是说,不需要为每个枚举类型定义新的转换器。为此,提供了足够的信息来进行
Convert
ConvertBack

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

调用时,此转换器纯粹基于
目标类型
值在int/enum值之间翻转值的类型。没有硬编码的枚举类型。

如何在
转换器中获取枚举类型
?我以前从未遇到过MarkupExtensions,谢谢!每天都在学习新东西:)事实上,这里也是一样,我刚开始使用它们,它们非常方便:)
    /// <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;
    }
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);
    }
}