[英]Is it possible to create a generic Int-to-Enum Converter?
我想能說
<DataTrigger Binding="{Binding SomeIntValue}"
Value="{x:Static local:MyEnum.SomeValue}">
如果int
值等於(int)MyEnum.Value
其解析為True
我知道我可以創建一個返回(MyEnum)intValue
的Converter
,但是我必須為我在DataTriggers中使用的每個Enum類型創建一個轉換器。
有沒有一種通用的方法來創建一個能夠提供這種功能的轉換器?
可以以可重用的方式在枚舉值及其底層整數類型之間創建轉換器 - 也就是說,您不需要為每個枚舉類型定義新的轉換器。 有提供足夠的信息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);
}
}
調用時,此轉換器僅基於value
和targetType
值在int / enum值之間翻轉值的類型。 沒有硬編碼的枚舉類型。
我想我明白了
我只需要設置我的ConverterParameter
而不是Value
等於我正在尋找的Enum,並評估為True / False
<DataTrigger Value="True"
Binding="{Binding SomeIntValue,
Converter={StaticResource IsIntEqualEnumConverter},
ConverterParameter={x:Static local:MyEnum.SomeValue}}">
變流器
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;
}
你也可以反過來使用自定義標記擴展將枚舉轉換為int的int。
例
<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;
}
}
我們過去也想過幾次這樣做,所以我們構建了幾個擴展方法(在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;
}
此實現處理具有任何基礎類型的枚舉,以及使用[Flags]屬性定義的枚舉。
您可以對int值執行ToString(),然后將其傳遞給靜態Enum.Parse或Enum.TryParse方法,該方法采用您關注的枚舉類型並返回適當的值。
這不是一個完美的解決方案,因為它不適用於表示多個枚舉值的二進制ORing的整數
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.