c# - Transistion from clockwise to counter-clockwise modes smoothly using WPF storyboard -
edit: project can downloaded here.
i using wpf storyboard animate earth rotation, , want able reverse rotation clockwise counter-clockwise (and vice versa) when user clicks button, although in reality should never happen.

in xaml file, declare 21 bitmapimages (the first , last identical) , 2 storyboards, 1 clockwisely rotation , other counter-clockwisely rotation.
<window x:class="stackoverflowwpf.storyboardseekwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" title="storyboardseekwindow" height="400" width="400"> <window.resources> <bitmapimage x:key="rotationimage0" urisource="images\rotation\0.png"/> <bitmapimage x:key="rotationimage1" urisource="images\rotation\1.png"/> <bitmapimage x:key="rotationimage2" urisource="images\rotation\2.png"/> <bitmapimage x:key="rotationimage3" urisource="images\rotation\3.png"/> <bitmapimage x:key="rotationimage4" urisource="images\rotation\4.png"/> <bitmapimage x:key="rotationimage5" urisource="images\rotation\5.png"/> <bitmapimage x:key="rotationimage6" urisource="images\rotation\6.png"/> <bitmapimage x:key="rotationimage7" urisource="images\rotation\7.png"/> <bitmapimage x:key="rotationimage8" urisource="images\rotation\8.png"/> <bitmapimage x:key="rotationimage9" urisource="images\rotation\9.png"/> <bitmapimage x:key="rotationimage10" urisource="images\rotation\10.png"/> <bitmapimage x:key="rotationimage11" urisource="images\rotation\11.png"/> <bitmapimage x:key="rotationimage12" urisource="images\rotation\12.png"/> <bitmapimage x:key="rotationimage13" urisource="images\rotation\13.png"/> <bitmapimage x:key="rotationimage14" urisource="images\rotation\14.png"/> <bitmapimage x:key="rotationimage15" urisource="images\rotation\15.png"/> <bitmapimage x:key="rotationimage16" urisource="images\rotation\16.png"/> <bitmapimage x:key="rotationimage17" urisource="images\rotation\17.png"/> <bitmapimage x:key="rotationimage18" urisource="images\rotation\18.png"/> <bitmapimage x:key="rotationimage19" urisource="images\rotation\19.png"/> <bitmapimage x:key="rotationimage20" urisource="images\rotation\20.png"/> <storyboard x:key="clockwisestoryboard" repeatbehavior="forever"> <objectanimationusingkeyframes storyboard.targetname="imgrotatingearth" storyboard.targetproperty="source"> <discreteobjectkeyframe keytime="0:0:0.0" value="{binding source={staticresource rotationimage0}}"/> <discreteobjectkeyframe keytime="0:0:0.2" value="{binding source={staticresource rotationimage1}}"/> <discreteobjectkeyframe keytime="0:0:0.4" value="{binding source={staticresource rotationimage2}}"/> <discreteobjectkeyframe keytime="0:0:0.6" value="{binding source={staticresource rotationimage3}}"/> <discreteobjectkeyframe keytime="0:0:0.8" value="{binding source={staticresource rotationimage4}}"/> <discreteobjectkeyframe keytime="0:0:1.0" value="{binding source={staticresource rotationimage5}}"/> <discreteobjectkeyframe keytime="0:0:1.2" value="{binding source={staticresource rotationimage6}}"/> <discreteobjectkeyframe keytime="0:0:1.4" value="{binding source={staticresource rotationimage7}}"/> <discreteobjectkeyframe keytime="0:0:1.6" value="{binding source={staticresource rotationimage8}}"/> <discreteobjectkeyframe keytime="0:0:1.8" value="{binding source={staticresource rotationimage9}}"/> <discreteobjectkeyframe keytime="0:0:2.0" value="{binding source={staticresource rotationimage10}}"/> <discreteobjectkeyframe keytime="0:0:2.2" value="{binding source={staticresource rotationimage11}}"/> <discreteobjectkeyframe keytime="0:0:2.4" value="{binding source={staticresource rotationimage12}}"/> <discreteobjectkeyframe keytime="0:0:2.6" value="{binding source={staticresource rotationimage13}}"/> <discreteobjectkeyframe keytime="0:0:2.8" value="{binding source={staticresource rotationimage14}}"/> <discreteobjectkeyframe keytime="0:0:3.0" value="{binding source={staticresource rotationimage15}}"/> <discreteobjectkeyframe keytime="0:0:3.2" value="{binding source={staticresource rotationimage16}}"/> <discreteobjectkeyframe keytime="0:0:3.4" value="{binding source={staticresource rotationimage17}}"/> <discreteobjectkeyframe keytime="0:0:3.6" value="{binding source={staticresource rotationimage18}}"/> <discreteobjectkeyframe keytime="0:0:3.8" value="{binding source={staticresource rotationimage19}}"/> <discreteobjectkeyframe keytime="0:0:4.0" value="{binding source={staticresource rotationimage20}}"/> </objectanimationusingkeyframes> </storyboard> <storyboard x:key="counterclockwisestoryboard" repeatbehavior="forever"> <objectanimationusingkeyframes storyboard.targetname="imgrotatingearth" storyboard.targetproperty="source"> <discreteobjectkeyframe keytime="0:0:0.0" value="{binding source={staticresource rotationimage20}}"/> <discreteobjectkeyframe keytime="0:0:0.2" value="{binding source={staticresource rotationimage19}}"/> <discreteobjectkeyframe keytime="0:0:0.4" value="{binding source={staticresource rotationimage18}}"/> <discreteobjectkeyframe keytime="0:0:0.6" value="{binding source={staticresource rotationimage17}}"/> <discreteobjectkeyframe keytime="0:0:0.8" value="{binding source={staticresource rotationimage16}}"/> <discreteobjectkeyframe keytime="0:0:1.0" value="{binding source={staticresource rotationimage15}}"/> <discreteobjectkeyframe keytime="0:0:1.2" value="{binding source={staticresource rotationimage14}}"/> <discreteobjectkeyframe keytime="0:0:1.4" value="{binding source={staticresource rotationimage13}}"/> <discreteobjectkeyframe keytime="0:0:1.6" value="{binding source={staticresource rotationimage12}}"/> <discreteobjectkeyframe keytime="0:0:1.8" value="{binding source={staticresource rotationimage11}}"/> <discreteobjectkeyframe keytime="0:0:2.0" value="{binding source={staticresource rotationimage10}}"/> <discreteobjectkeyframe keytime="0:0:2.2" value="{binding source={staticresource rotationimage9}}"/> <discreteobjectkeyframe keytime="0:0:2.4" value="{binding source={staticresource rotationimage8}}"/> <discreteobjectkeyframe keytime="0:0:2.6" value="{binding source={staticresource rotationimage7}}"/> <discreteobjectkeyframe keytime="0:0:2.8" value="{binding source={staticresource rotationimage6}}"/> <discreteobjectkeyframe keytime="0:0:3.0" value="{binding source={staticresource rotationimage5}}"/> <discreteobjectkeyframe keytime="0:0:3.2" value="{binding source={staticresource rotationimage4}}"/> <discreteobjectkeyframe keytime="0:0:3.4" value="{binding source={staticresource rotationimage3}}"/> <discreteobjectkeyframe keytime="0:0:3.6" value="{binding source={staticresource rotationimage2}}"/> <discreteobjectkeyframe keytime="0:0:3.8" value="{binding source={staticresource rotationimage1}}"/> <discreteobjectkeyframe keytime="0:0:4.0" value="{binding source={staticresource rotationimage0}}"/> </objectanimationusingkeyframes> </storyboard> </window.resources> <grid> <image x:name="imgrotatingearth" horizontalalignment="center" margin="50" stretch="uniform" /> <button verticalalignment="bottom" content="reverse" height="30" width="100" click="reversebutton_click" /> </grid> and code behind file
using system; using system.collections.generic; using system.linq; using system.text; using system.windows; using system.windows.controls; using system.windows.data; using system.windows.documents; using system.windows.input; using system.windows.media; using system.windows.media.imaging; using system.windows.shapes; using system.windows.media.animation; namespace stackoverflowwpf { /// <summary> /// interaction logic storyboardseekwindow.xaml /// </summary> public partial class storyboardseekwindow : window { storyboard clockwisestoryboard; storyboard counterclockwisestoryboard; bool brotateclockwisely; timespan duration = new timespan(0, 0, 4); double dprogress = 0; //the value of dprogress 0.0 (begin) 1.0 (end) public storyboardseekwindow() { initializecomponent(); clockwisestoryboard = this.findresource("clockwisestoryboard") storyboard; counterclockwisestoryboard = this.findresource("counterclockwisestoryboard") storyboard; startrotation(); } private void startrotation() { counterclockwisestoryboard.begin(); counterclockwisestoryboard.pause(); clockwisestoryboard.begin(); brotateclockwisely = true; } private void reversebutton_click(object sender, routedeventargs e) { storyboard sbactive = brotateclockwisely ? clockwisestoryboard : counterclockwisestoryboard; storyboard sbpaused = brotateclockwisely ? counterclockwisestoryboard : clockwisestoryboard; sbactive.pause(); //i want other storyboard can seek animation paused. dprogress = sbactive.getcurrentprogress(); dprogress = 1.0 - dprogress; sbpaused.seek(new timespan((long)(duration.ticks * dprogress))); sbpaused.resume(); brotateclockwisely = !brotateclockwisely; } } } in order smooth transition clockwise counter-clockwise mode, pause active animation , calculate frame in, when resume reverse animation, first seek frame. in order words, want achieve effect.
0.png->1.png->2.png->3.png->4.png->5.png->user clicks button->5.png->4.png->3.png->2.png->1.png->0.png->...
but code not work. storyboard.seek() seems working, not start rotating reversely. think might wrong in running 2 storyboards manipulate same object.
could me fix bugs, , perhaps provide better idea achieve same effect?
you might 'barking wrong tree' here images... how trying instead?:
<bitmapimage x:key="rotationimage0" urisource="images\rotation\0.png"> <bitmapimage.rendertransform> <rotatetransform x:name="rotatetransform" centerx="50" centery="50" angle="0" /> </bitmapimage.rendertransform> </bitmapimage> <bitmapimage.style> <style> <style.triggers> <datatrigger binding="{binding isloading, mode=oneway}" value="true"> <setter property="control.visibility" value="visible" /> <datatrigger.enteractions> <stopstoryboard beginstoryboardname="reverserotationstoryboard" /> <beginstoryboard name="rotationstoryboard"> <storyboard repeatbehavior="forever"> <doubleanimation storyboard.targetproperty="rendertransform. (rotatetransform.angle)" from="0" to="360" duration="0:0:2.0" /> </storyboard> </beginstoryboard> </datatrigger.enteractions> <datatrigger.exitactions> <stopstoryboard beginstoryboardname="rotationstoryboard" /> <beginstoryboard name="reverserotationstoryboard"> <storyboard repeatbehavior="forever"> <doubleanimation storyboard.targetproperty="rendertransform. (rotatetransform.angle)" from="360" to="0" duration="0:0:2.0" /> </storyboard> </beginstoryboard> </datatrigger.exitactions> </datatrigger> </style.triggers> </style> </bitmapimage.style> if require distinct 'steps' in animation, replace doubleanimation above following:
<doubleanimationusingkeyframes storyboard.targetproperty="rendertransform. (rotatetransform.angle)" duration="0:0:0.9"> <discretedoublekeyframe value="0" keytime="0:0:0" /> <discretedoublekeyframe value="30" keytime="0:0:0.075" /> <discretedoublekeyframe value="60" keytime="0:0:0.150" /> ... <discretedoublekeyframe value="330" keytime="0:0:0.825" /> </doubleanimationusingkeyframes> this works binding boolean property called isloading (adapted program). can call property whatever like, idea set false reverse direction of animation. trust able set property dependent on user's click.
notice storyboard in datatrigger.enteractions section... occurs property 'becomes' true. @ storyboard in datatrigger.exitactions section... occurs when property ceases true, or 'becomes' false.
Comments
Post a Comment