用于数据绑定的通用枚举 <-> Int 转换器

Generic Enum <-> Int converter for data binding

是否可以在枚举值和整数之间创建通用转换器? 我的项目中有一组类似的转换器:

Object^ SpecificEnumIntConverter::Convert(Object^ value, TypeName targetType, Object^ parameter, String^ language)
{
    const auto asEnum = static_cast<SpecificEnumType>(value);
    const auto asInt = static_cast<int>(asEnum);
    return asInt;
}

Object^ SpecificEnumIntConverter::ConvertBack(Object^ value, TypeName targetType, Object^ parameter, String^ language)
{
    const auto asInt = static_cast<int>(value);
    const auto asEnum = static_cast<SpecificEnumType>(asInt);
    return asEnum;
}

这些转换器通常用于与 ViewModel 绑定,即:

<ListBox SelectedIndex="{x:Bind VM.EnumTypeProperty, Mode=TwoWay, Converter={StaticResource SpecificEnumIntConverter}}">

我想知道是否可以实现通用转换器。

在此先致谢并致以最诚挚的问候!

您可以尝试以下解决方法:

使用一个变量typeFullName来保存枚举类型,以便以后在ConvertBack方法中使用来确定目标枚举的类型class。

public ref class SpecificEnumIntConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
private:
    Platform::String^ typeFullName;
public:
    virtual Platform::Object^ Convert(Platform::Object^ value, Windows::UI::Xaml::Interop::TypeName targetType,
        Platform::Object^ parameter, Platform::String^ language)
    {            
        typeFullName = value->GetType()->FullName;
        EnumType1 enum1 = EnumType1::red;
        EnumType2 enum2 = EnumType2::red;
        
        if (typeFullName == enum1.GetType()->FullName)
        {
            const auto asEnum = static_cast<EnumType1>(value);
            const auto asInt = static_cast<int>(asEnum);                
            return asInt;
        }
        else if(typeFullName == enum2.GetType()->FullName)
        {
            const auto asEnum = static_cast<EnumType2>(value);
            const auto asInt = static_cast<int>(asEnum);
            return asInt;
        }
    }

    // No need to implement converting back on a one-way binding 
    virtual Platform::Object^ ConvertBack(Platform::Object^ value, Windows::UI::Xaml::Interop::TypeName targetType,
        Platform::Object^ parameter, Platform::String^ language)
    {
        if (typeFullName != nullptr)
        {
            EnumType1 enum1 = EnumType1::red;
            EnumType2 enum2 = EnumType2::red;

            if (typeFullName == enum1.GetType()->FullName)
            {
                const auto asInt = static_cast<int>(value);
                const auto asEnum = static_cast<EnumType1>(asInt);
                return asEnum;
            }
            else if (typeFullName == enum2.GetType()->FullName)
            {
                const auto asInt = static_cast<int>(value);
                const auto asEnum = static_cast<EnumType2>(asInt);
                return asEnum;
            }
        }
    }
};

EnumType1EnumType2 是示例枚举类型,红色是枚举中的成员 class.

可以通过某种方式使用模板<...> 定义通用转换器。

public enum class EnumType1 : int
{
    Foo1, Bar1
};
public enum class EnumType2 : int
{
    Foo2, Bar2
};

// C++/CLI's syntax "generic<...> public ref class ... " cannot be used in C++/CX.

template <class _T>
ref class GenericEnumConverter : Windows::UI::Xaml::Data::IValueConverter
{
public:
    virtual Platform::Object ^ Convert(Platform::Object ^value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^parameter, Platform::String ^language)
    {
        const auto asEnum = static_cast<_T>(value);
        const auto asInt = static_cast<int>(asEnum);
        return asInt;
    }
    virtual Platform::Object ^ ConvertBack(Platform::Object ^value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^parameter, Platform::String ^language)
    {
        const auto asInt = static_cast<int>(value);
        const auto asEnum = static_cast<_T>(asInt);
        return asEnum;
    }
};

然而,不可能通过 XAML 将此类转换器直接放置在资源中(因为 C++/CX 中的模板化-class 不能采用“public”可访问性修饰符)。所以你需要在代码后面部署它们。

[Windows::Foundation::Metadata::WebHostHidden]
public ref class MainPage sealed
{
public:
    MainPage()
    {
        Resources->Insert(L"EnumType1Converter", ref new GenericEnumConverter<EnumType1>());
        Resources->Insert(L"EnumType2Converter", ref new GenericEnumConverter<EnumType2>());

        InitializeComponent();
    }

    property EnumType1 Value1 {
        EnumType1 get() { return m_Value1; }
        void set(EnumType1 value) {
            m_Value1 = value; 
            //OutputDebugString((m_Value1.ToString() + L"\r")->Begin());
        }
    }
    property EnumType2 Value2 { 
        EnumType2 get() { return m_Value2; }
        void set(EnumType2 value) { 
            m_Value2 = value;
            //OutputDebugString((m_Value2.ToString() + L"\r")->Begin());
        }
    }
private:
    EnumType1 m_Value1 = EnumType1::Foo1;
    EnumType2 m_Value2 = EnumType2::Bar2;
};

然后就可以在绑定中使用转换器了。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <ListBox SelectedIndex="{x:Bind Value1, Converter={StaticResource EnumType1Converter}, Mode=TwoWay}" Margin="16">
            <ListBoxItem>Foo1</ListBoxItem>
            <ListBoxItem>Bar1</ListBoxItem>
        </ListBox>
        <ListBox SelectedIndex="{x:Bind Value2, Converter={StaticResource EnumType2Converter}, Mode=TwoWay}" Margin="16">
            <ListBoxItem>Foo2</ListBoxItem>
            <ListBoxItem>Bar2</ListBoxItem>
        </ListBox>
    </StackPanel>
</Grid>