Antrophy
Topic Author
Posts: 3
Joined: 02 Oct 2021, 16:21

Unable to transfer animation from C# to C++, says property is in "read-only state"

08 Mar 2022, 20:12

Hello,

I have a custom control that will be used as a navigation bar with a select animation. I first created it in C# and it works fine as you can see on the youtube video.

This is the code that sets the animation into motion in C#:
double targetPosition = topOffset; // + point.Y;

IndicatorPositionAnimation.KeyFrames[0].Value = PreviousPosition;
IndicatorPositionAnimation.KeyFrames[0].KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);
IndicatorPositionAnimation.KeyFrames[1].Value = targetPosition;
IndicatorPositionAnimation.KeyFrames[1].KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0,0,0,0,200));

Transform trackRenderTransform = IndicatorTrack.RenderTransform;

if (trackRenderTransform is TranslateTransform translateTransform)
{
	translateTransform.BeginAnimation(TranslateTransform.YProperty, IndicatorPositionAnimation);
}

IndicatorSizeAnimation.KeyFrames[0].Value = PreviousSize;
IndicatorSizeAnimation.KeyFrames[0].KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero);
IndicatorSizeAnimation.KeyFrames[1].Value = item.ActualHeight;
IndicatorSizeAnimation.KeyFrames[1].KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 200));

IndicatorTrack.BeginAnimation(HeightProperty, IndicatorSizeAnimation);

PreviousPosition = targetPosition;
PreviousSize = item.ActualHeight;
And here it is in the C++
const float targetPosition = topOffset;

IndicatorPositionAnimation->GetKeyFrames()->Get(0)->SetValue(PreviousPosition);
IndicatorPositionAnimation->GetKeyFrames()->Get(0)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan::Zero()));
IndicatorPositionAnimation->GetKeyFrames()->Get(1)->SetValue(targetPosition);
IndicatorPositionAnimation->GetKeyFrames()->Get(1)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan(0,0,0,0,200)));

Transform* trackRenderTransform = IndicatorTrack->GetRenderTransform();
TranslateTransform* translateTransform = DynamicCast<TranslateTransform*>(trackRenderTransform);
if (translateTransform != 0)
{
	IndicatorPositionAnimation->Start(translateTransform, TranslateTransform::YProperty, GetTimeManager());
}
		
IndicatorSizeAnimation->GetKeyFrames()->Get(0)->SetValue(PreviousSize);
IndicatorSizeAnimation->GetKeyFrames()->Get(0)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan::Zero()));
IndicatorSizeAnimation->GetKeyFrames()->Get(1)->SetValue(item->GetActualHeight());
IndicatorSizeAnimation->GetKeyFrames()->Get(1)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan(0,0,0,0,200)));

IndicatorSizeAnimation->Start(IndicatorTrack, HeightProperty, GetTimeManager());

PreviousPosition = targetPosition;
PreviousSize = targetSize;
Whenever it tries to start the "moving" animation it says:
LogNoesis: Warning: Cannot set 'y' property on object 'TranslateTransform' because it is in a read-only state
.
What is wrong or what should I do differently to get this animation running? It works fine in C# and it doesn't complain about the property being in read-only state.
 
User avatar
sfernandez
Site Admin
Posts: 3363
Joined: 22 Dec 2011, 19:20

Re: Unable to transfer animation from C# to C++, says property is in "read-only state"

10 Mar 2022, 10:34

Hi, this error message means that a Frozen element (the TranslateTransform) is modified (by the animation). Could you please share the xaml where you define the TrackIndicator and the animation? Is this part of a template? I want to check what are we doing different from WPF.

In the meantime you can use a Storyboard to animate both properties by targeting the TrackIndicator, something like this:
const float targetPosition = topOffset;

Storyboard::SetTarget(IndicatorPositionAnimation, IndicatorTrack);
Storyboard::SetTargetProperty(IndicatorPositionAnimation, MakePtr<PropertyPath>("RenderTransform.Y"));
IndicatorPositionAnimation->GetKeyFrames()->Get(0)->SetValue(PreviousPosition);
IndicatorPositionAnimation->GetKeyFrames()->Get(0)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan::Zero()));
IndicatorPositionAnimation->GetKeyFrames()->Get(1)->SetValue(targetPosition);
IndicatorPositionAnimation->GetKeyFrames()->Get(1)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan(0,0,0,0,200)));

Storyboard::SetTarget(IndicatorSizeAnimation, IndicatorTrack);
Storyboard::SetTargetProperty(IndicatorSizeAnimation, MakePtr<PropertyPath>("Height"));
IndicatorSizeAnimation->GetKeyFrames()->Get(0)->SetValue(PreviousSize);
IndicatorSizeAnimation->GetKeyFrames()->Get(0)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan::Zero()));
IndicatorSizeAnimation->GetKeyFrames()->Get(1)->SetValue(item->GetActualHeight());
IndicatorSizeAnimation->GetKeyFrames()->Get(1)->SetKeyTime(KeyTime::FromTimeSpan(TimeSpan(0,0,0,0,200)));

Ptr<Storyboard> storyboard = MakePtr<Storyboard>();
storyboard->GetChildren()->Add(IndicatorPositionAnimation);
storyboard->GetChildren()->Add(IndicatorSizeAnimation);
storyboard->Begin(IndicatorTrack);

PreviousPosition = targetPosition;
PreviousSize = targetSize;
In this case the storyboard is able to detect frozen elements in the animation property path, and clone them, so they can be animated.

Who is online

Users browsing this forum: No registered users and 6 guests