CustomConverter: What is the target type of a DoubleAnimation targeting RenderTransform.X?
Hey everyone,
simple question and maybe obvious to answer... but is it? As it is a DOUBLEAnimation, "double" seems to be obvious, but Noesis uses floats in C++ for performance reasons. So I would expect that "float" is the correct answer here. The error message hints towards "Int32" which makes sense because we target a pixel position in screen space. But it isn't?!
I am working on a DoubleAnimation to animate the RenderTransform.X of a ListBox. The way I do it works in a general WPF project, but I can't get it to run in c++. Clearly, my custom converter is the issue because I cannot figure out which type I need to "Noesis::Boxing::Box<>" my return value into. It always returns false with the message: " 'SomeCompany.VisualConcept.MVVM.View.ConvertIndexToRenderTransformX' binding converter failed to convert value '0' (type 'Int32')"
So what type do I need to box my return value into?
As you can see in the following code, I checked for many types, but none of the if conditions are ever true.
And for reference, the ListBox I am working on:
simple question and maybe obvious to answer... but is it? As it is a DOUBLEAnimation, "double" seems to be obvious, but Noesis uses floats in C++ for performance reasons. So I would expect that "float" is the correct answer here. The error message hints towards "Int32" which makes sense because we target a pixel position in screen space. But it isn't?!
I am working on a DoubleAnimation to animate the RenderTransform.X of a ListBox. The way I do it works in a general WPF project, but I can't get it to run in c++. Clearly, my custom converter is the issue because I cannot figure out which type I need to "Noesis::Boxing::Box<>" my return value into. It always returns false with the message: " 'SomeCompany.VisualConcept.MVVM.View.ConvertIndexToRenderTransformX' binding converter failed to convert value '0' (type 'Int32')"
So what type do I need to box my return value into?
As you can see in the following code, I checked for many types, but none of the if conditions are ever true.
Code: Select all
class ConvertIndexToRenderTransformX : public Noesis::BaseValueConverter
{
public:
bool TryConvert(Noesis::BaseComponent* value, const Noesis::Type* targetType, Noesis::BaseComponent* parameter,
Noesis::Ptr<Noesis::BaseComponent>& result) override
{
if (targetType == Noesis::TypeOf<bool>()) {
DEBUG_ERROR("bool");
}
if (targetType == Noesis::TypeOf<int8_t>()) {
DEBUG_ERROR("int8_t");
}
if (targetType == Noesis::TypeOf<int16_t>()) {
DEBUG_ERROR("int16_t");
}
if (targetType == Noesis::TypeOf<int32_t>()) {
DEBUG_ERROR("int32_t");
}
if (targetType == Noesis::TypeOf<int64_t>()) {
DEBUG_ERROR("int64_t");
}
if (targetType == Noesis::TypeOf<uint8_t>()) {
DEBUG_ERROR("uint8_t");
}
if (targetType == Noesis::TypeOf<uint16_t>()) {
DEBUG_ERROR("uint16_t");
}
if (targetType == Noesis::TypeOf<uint32_t>()) {
DEBUG_ERROR("uint32_t");
}
if (targetType == Noesis::TypeOf<uint64_t>()) {
DEBUG_ERROR("uint64_t");
}
if (targetType == Noesis::TypeOf<int>()) {
DEBUG_ERROR("int");
}
if (targetType == Noesis::TypeOf<signed int>()) {
DEBUG_ERROR("signed int");
}
if (targetType == Noesis::TypeOf<float>()) {
DEBUG_ERROR("Float");
}
if (targetType == Noesis::TypeOf<double>()) {
DEBUG_ERROR("double");
}
/*if (targetType == Noesis::TypeOf<short>()) {
DEBUG_ERROR("short");
}
if (targetType == Noesis::TypeOf<long>()) {
DEBUG_ERROR("long");
}*/
if (targetType == Noesis::TypeOf<char>()) {
DEBUG_ERROR("char");
}
if (targetType == Noesis::TypeOf<Noesis::String>()) {
DEBUG_ERROR("Noesis::String");
}
if (targetType == Noesis::TypeOf<Noesis::Symbol>()) {
DEBUG_ERROR("Noesis::Symbol");
}
if (targetType == Noesis::TypeOf<Noesis::Point>()) {
DEBUG_ERROR("Noesis::Point");
}
if (targetType == Noesis::TypeOf<Noesis::TransformGroup>()) {
DEBUG_ERROR("Noesis::TransformGroup");
}
if (targetType == Noesis::TypeOf<float>() &&
Noesis::Boxing::CanUnbox<int>(value)) {
result = Noesis::Boxing::Box<float>(static_cast<float>(Noesis::Boxing::Unbox<int>(value) * -10.0));
return true;
}
return false;
}
bool TryConvertBack(Noesis::BaseComponent* value, const Noesis::Type* targetType, Noesis::BaseComponent* parameter, Noesis::Ptr<Noesis::BaseComponent>& result) override
{
ASSERT_UNREACHABLE("ConvertIndexToRenderTransformX::TryConvertBack() Not yet implemented [Manuel]");
return false;
}
private:
NS_IMPLEMENT_INLINE_REFLECTION_(ConvertIndexToRenderTransformX, Noesis::BaseValueConverter, "SomeCompany.VisualConcept.MVVM.View.ConvertIndexToRenderTransformX")
};
Code: Select all
<ListBox x:Name="EpisodeList">
<ListBox.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</ListBox.RenderTransform>
<ListBox.Resources>
<Storyboard x:Key="MoveAnimation">
<DoubleAnimation To="{Binding SelectedEpisodeIndex, Converter={StaticResource ConvertIndexToRenderTransformX}}" Storyboard.TargetProperty="RenderTransform.X" Storyboard.TargetName="EpisodeList" Duration="00:00:00.250000" FillBehavior="HoldEnd" IsAdditive="True" IsCumulative="True"/>
<DoubleAnimation To="{Binding SelectedEpisodeIndex, Converter={StaticResource ConvertIndexToRenderTransformY}}" Storyboard.TargetProperty="RenderTransform.Y" Storyboard.TargetName="EpisodeList" Duration="00:00:00.250000" FillBehavior="HoldEnd" IsAdditive="True" IsCumulative="True"/>
</Storyboard>
</ListBox.Resources>
<behaviors:Interaction.Triggers>
<behaviors:PropertyChangedTrigger Binding="{Binding SelectedEpisodeIndex}">
<behaviors:ControlStoryboardAction Storyboard="{StaticResource MoveAnimation}"/>
</behaviors:PropertyChangedTrigger>
</behaviors:Interaction.Triggers>
</ListBox>
-
sfernandez
Site Admin
- Posts: 2995
- Joined:
Re: CustomConverter: What is the target type of a DoubleAnimation targeting RenderTransform.X?
Hi Manuel,
The "To" property of a DoubleAnimation is a nullable (in WPF a Nullable<double>, and in Noesis a Nullable<float>).
So your converter implementation can return a float or a nullptr result.
Cheers.
The "To" property of a DoubleAnimation is a nullable (in WPF a Nullable<double>, and in Noesis a Nullable<float>).
Code: Select all
class NS_GUI_ANIMATION_API DoubleAnimation: public DoubleAnimationBase
{ ...
/// Gets or sets the animation's ending value
//@{
const Nullable<float>& GetTo() const;
void SetTo(const Nullable<float>& to);
//@}
... };
Code: Select all
bool TryConvert(Noesis::BaseComponent* value, const Noesis::Type* targetType, Noesis::BaseComponent* parameter,
Noesis::Ptr<Noesis::BaseComponent>& result) override
{
if (targetType == Noesis::TypeOf<Noesis::Nullable<float>>() && Noesis::Boxing::CanUnbox<int>(value)) {
result = Noesis::Boxing::Box<float>(Noesis::Boxing::Unbox<int>(value) * -10.0f);
return true;
}
return false;
}
Re: CustomConverter: What is the target type of a DoubleAnimation targeting RenderTransform.X?
By the way you can get the type (and name) of any BaseObject by doing:
Code: Select all
obj->GetClassType()->GetName();
Re: CustomConverter: What is the target type of a DoubleAnimation targeting RenderTransform.X?
Thanks to both of you. That helped a lot. I totally forget about the Nullables. Though I am a bit confused why I do check for a Nullable<float> but do only return Box<float> and not Box<Nullable<float>>. I checked both and cannot spot a difference, though I do not make use of NULL.
And none of the following returns the string "Box<float>" which isn't very insightful:
And none of the following returns the string "Box<float>" which isn't very insightful:
Code: Select all
targetType->GetClassType()->GetName() returns "TypeClass"
value->GetClassType()->GetName() returns "Boxed<Int32>"
result->GetClassType()->GetName() returns "Boxed<Int32>"
-
sfernandez
Site Admin
- Posts: 2995
- Joined:
Re: CustomConverter: What is the target type of a DoubleAnimation targeting RenderTransform.X?
Boxing a nullable will return null if it has no value or will box the underlying type:
So having a float value it doesn't matter if you box it as Nullable<float> or float, as the result will be the same.
Regarding the type names, for the targetType, as it is already a type, you want to get its name directly:
Code: Select all
Ptr<BoxedValue> boxed1 = Boxing::Box(Nullable<float>()); // boxed1 will be nullptr
Ptr<BoxedValue> boxed2 = Boxing::Box(Nullable<float>(123.0f)); // boxed2 will store a simple float
Regarding the type names, for the targetType, as it is already a type, you want to get its name directly:
Code: Select all
targetType->GetName() // should return "Nullable<Single>" in this case
Who is online
Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 25 guests