我们讲过如何加载一个XAML-based用户界面到我们的应用程序中,并截获程序产生的事件。

这篇文章我们会学习如何使用故事板(storyboard)在我们的用户界面上创建动画,并介绍如何从代码中控制这些动画。

我们使用Expression Blend 2重新打开Silverlight 2 application project,并添加一个新的元素到UI上:TextBlock。



我将其放置在Button下面:



然后我们就可以使用“+”按钮(在”Objects and Timeline”标题下面)创建一个新的storyboard:



我们给新的storyboard分配一个名字方便后面操作:



我们将storyboard的时间光标移至1s处:



旋转TextBlock:



Expression Blend为我们创建动画和呈现指定的视觉效果所需要的中间对象(transformation objects)。

我们让TextBlock执行一个360度旋转:



通过在tranform item上右击设置动画的重复次数。我们设置一直重复:



保存项目返回Platform Builder修改代码。

首先通过FindName从visual root获得指向stroyboard的指针,就像之前我们取得button对象的指针一样。



​​


1

2

3

4

5




​IXRStoryboardPtr sboard;​


​if​​​​(FAILED(retcode=root->FindName(TEXT(​​​​"SpinText"​​​​), &sboard)))​


​    ​​​​return​​​​-1;​





我们需要在event handler类使用storyboard和button对象,所以修改它以便储存这2个对象的智能指针。



​​


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18




​class​​​​BtnEventHandler​


​{​


​protected​​​​:​


​    ​​​​IXRButtonBasePtr    btn;​


​    ​​​​IXRStoryboardPtr     sboard;​


​public​​​​:​


​    ​​​​BtnEventHandler(IXRButtonBasePtr& button, IXRStoryboardPtr& storyboard) : btn(button),sboard(storyboard)​


​    ​​​​{   ​


​    ​​​​}​​​​}​




修改在WinMain函数中的声明:




1




​BtnEventHandler handler(btn,sboard);​





编辑OnClick event handler以便控制开始和停止按钮的旋转动画。

先通过获得storyboard对象的属性来判断动画是否在进行中:



​​


1

2

3

4

5

6

7




​HRESULT​​​​retcode;​


​XRClockState ckstate;​


​if​​​​(FAILED(retcode=sboard->GetCurrentState(&ckstate)))​


​    ​​​​return​​​​retcode;​




如果ckstate的值是XRClockState_Stopped,说明我们的动画是停止的,那么使用storyboard对象的Begin方法启动它。

同样如果动画是运行的,我们通过Stop方法停止它。

同时我们还想改变button的text以便反应它正执行的动作。IXRButton对象(COM interface) 继承自IXRContentContro对象,IXRContentContro对象定义了访问"content"的方法。

那么SE对象的"content"到底是什么?

其实它是XRValue 类的一个实例。XRValue类包含了不同的值:字符串(strings)、数字(numbers)、坐标(coordinates)等。它当前的值类型(content type)是通过vType字段来指定的,vType可以是枚举类型VALUE_TYPE 的一个值:



​​


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15




​VTYPE_NONE = 0,​​​​VTYPE_FLOAT = 1,​​​​VTYPE_INT = 2,​​​​VTYPE_BOOL = 3,​​​​VTYPE_UINT = 4,​​​​VTYPE_COLOR = 5,​​​​VTYPE_READONLY_STRING = 6,​​​​VTYPE_BSTR = 7​​​​VTYPE_POINT = 8,​​​​VTYPE_RECT = 9,​​​​VTYPE_THICKNESS = 10,​​​​VTYPE_SIZE = 11,​​​​VTYPE_GRIDLENGTH = 12,​​​​VTYPE_CORNER_RADIUS = 13,​​​​VTYPE_OBJECT = 14​




XRValue对象是否让你想起COM中的VARIANT对象?

在此我们定义一个只读的字符串(read only string)作为button的content:



​​


1

2

3




​XRValue btnvalue;​


​btnvalue.vType=VTYPE_READONLY_STRING;​




我们通过pReadOnlyStringVal字段来赋给按钮的值是"Spin!" 还是"Stop!",当然我们是根据动画的当前状态来判断的。

全部的enent handler代码是这样的:



​​


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47




​HRESULT​​​​OnClick(IXRDependencyObject* source,XRMouseButtonEventArgs* args)​


​{​


​    ​​​​HRESULT​​​​retcode;​


​    ​​​​XRClockState ckstate;​


​    ​​​​if​​​​(FAILED(retcode=sboard->GetCurrentState(&ckstate)))​


​        ​​​​return​​​​retcode;​


​    ​​​​XRValue btnvalue;​


​    ​​​​btnvalue.vType=VTYPE_READONLY_STRING;​


​    ​​​​if​​​​(ckstate==XRClockState_Stopped)​


​    ​​​​{​


​        ​​​​btnvalue.pReadOnlyStringVal=L​​​​"Stop!"​​​​;​


​        ​​​​if​​​​(FAILED(retcode=sboard->Begin()))​


​            ​​​​return​​​​retcode;​


​    ​​​​}​


​    ​​​​else​


​    ​​​​{​


​        ​​​​btnvalue.pReadOnlyStringVal=L​​​​"Spin!"​​​​;​


​        ​​​​if​​​​(FAILED(retcode=sboard->Stop()))​


​            ​​​​return​​​​retcode;​


​    ​​​​}​


​    ​​​​if​​​​(FAILED(retcode=btn->SetContent(&btnvalue)))​


​        ​​​​return​​​​retcode;​


​    ​​​​return​​​​S_OK;​


​}​




你可以从这里下载Demo的代码: