用于数据绑定的通用枚举 <-> 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;
}
}
}
};
EnumType1
和 EnumType2
是示例枚举类型,红色是枚举中的成员 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>
是否可以在枚举值和整数之间创建通用转换器? 我的项目中有一组类似的转换器:
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;
}
}
}
};
EnumType1
和 EnumType2
是示例枚举类型,红色是枚举中的成员 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>