[SilverLight1.1入门] Getting started:模拟时钟
很多人都已经开始了SilverLight的学习,虽然对于M$的产品需要牺牲很多小白鼠才能够比较稳定,今天我也来当当小白鼠。我选择的是SilverLight1.1(C#)当然是Alpha版本的,虽然JS在Orcas([JS.IntelliSense]VS2008(Orcas) So Cool)中也已经不算什么难的事情了,但是我还是觉得C#比较好一点。当我装上SilverLight开发所需要的所有器械后,拿出来的第一个Getting started例子就是Clock,但是惨不忍睹啊,编译通不过。对于第一次学习这个东东,我哪知道错在什么地方,好像那个例子是用JS写后改过来的,总之在我用是就不能通过了。还好找到了另一篇文章来帮助我完成了这个例子,OK,闲话不多说了,本文将讲解SilverLight的几个基础,并一步一步的带你走完“模拟时钟”。
首先我们新建一个silverLight项目,在C#语言选择栏下面可以找到SilverLight然后建立项目Clock。Orcas会为我们生成几个文件,我们就可以直接利用他们来为我们完成这个学习例子。
从上面我们可以看出Page.xaml就是我们所要讲的主角,Page.xaml.cs是处理Page.xaml文件的(aspx,aspx.cs),silverlight.js是我们创建控件是要用的脚本,还有一个脚本是在TestPage.html中创建当前控件用的。OK我们打开Page.xaml看看他们为我们做好了什么?代码如下:
和ASP.NET中aspx页面一样,每一个元素都与.NET CLR类关联。从上面的代码我们可以看出xmlns为XML命名空间,至于有什么用处其实我也说不清,反正他自动增加的就放着吧。我们可以看到上面有一个以"x:"为前缀的属性(如果是我们自己写的就用其他前缀,和ASP.NET中自定义服务器控件注册一样),这个相当于ASP.NET中的"asp:"前缀就是注册了控件一样,也就是说以"x:"为前缀的属性在服务端可以获取,例如上面的"x:Name"在服务端就会为我们生成一个ID,我们可以通过这个ID来调用当前XAML(相当于ASP.NET服务器控件中的ID),x:Class是表示当前XAML和哪个类相关联。
我们还可以引入一个程序集,我们自己的类等等,值得注意的是Loaded这个属性的值和Page.xaml.cs中的方法是一至的,如果不一致将出现错误。OK接下来我们来看看这个例子,这个例子的最终效果图如下:
万丈高楼平地起,我们写这个程序当然也是要从底层做起,我用Blend2 May 2007打开但是不怎么会用,虽然画了图但是不知道怎么去颜色,怎么填充颜色,所以还是一步一步的建起。首先我们要画出最底层的阴影,代码如下:
你可以按F5看看效果,从上面可以知道,我们画了一个宽高为305(直径)的圆,其中圆的顶端据canvas的距离是117,左边据canvas的距离也为117,不透明度为0.3。通过上面的说明大家也应该知道各个属性的用途了,这里就不多说了。我们可以看到如下效果:
接着我们通过设置StrokeThickness(厚度:我也不知道怎么说,总之是内圆和外圆半径差值)来画一个环形,然后设定两端颜色线性渐变。代码如下:
我们可以按F5看看效果,是不是我们想象的那样,如果我猜的没有错的话Ellipse.Stroke是取得圆环部分,通过LinearGradientBrush刷子来进行填涂(不知道用什么术语),然后设置起点和终点的颜色等,效果如下:
然后我们在添加圆上的线,用黑色画圈这样显得更好看一点,以同样的原理画厚度为10的环形,在加入圆圈线等,代码如下:
按F5可以看到如下效果:
现在我们所剩下的工作就是画上指针hour,minute,second。用Polygon可以画多边形,通过Points属性来确定断点坐标。我们在通过Line来画线(second), 代码如下:
我们可以看到效果如下:
这个是不会动的始钟,下面我们要做的是就是让时钟走起来,所以要涉及到行为等问题,我们在上面定义时钟指针时都有给他们加入x:Name属性,也就是说我们给他们一个ID。我们可以将事件绑定到指针中(事件触发器),代码如下:
从上述代码中我们可以知道,这个时间触发的事件由Canvas.Loaded来触发,这个对应的是<Canvas/>的Loaded属性。然后我们通过DoubleAnimation来管理各个控件,Storyboard.TargetName和刚刚画好的控件绑定,将Storyboard.TargetProperty设置为角度"Angle",永远的重复执行,就是将RepeatBehavior设置为Forever,Duration设置为什么时候是才是一圈(可能是这样,太晚了不查资料了...)。接下来要做的就是通过cs文件来控制转速,代码如下,谁都看得懂:
其实只要你在控件(?应该是叫控件)用x:Name标注,在服务端的InitializeComponent(); 中就会自动为你生产如下代码:Polygon Minutes;...Minutes= this.FindName("Minutes") as Polygon;这样我们就可以直接用了,最后运行一下就OK了。这是我的第一次和SilverLight打交道,如果有什么错误的地方还请多多指教。
你可以从这里下载源代码:SourceCode
(本文的主要程序来源于:http://dotnetslackers.com/articles/silverlight/SilverlightFirstStepsAnalogClock.aspx)
首先我们新建一个silverLight项目,在C#语言选择栏下面可以找到SilverLight然后建立项目Clock。Orcas会为我们生成几个文件,我们就可以直接利用他们来为我们完成这个学习例子。
从上面我们可以看出Page.xaml就是我们所要讲的主角,Page.xaml.cs是处理Page.xaml文件的(aspx,aspx.cs),silverlight.js是我们创建控件是要用的脚本,还有一个脚本是在TestPage.html中创建当前控件用的。OK我们打开Page.xaml看看他们为我们做好了什么?代码如下:
1 <Canvas
2 xmlns="http://schemas.microsoft.com/client/2007"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 x:Name="parentCanvas"
5 Loaded="Page_Loaded"
6 x:Class="Clock.Page;assembly=ClientBin/Clock.dll"
7 Width="640"
8 Height="480"
9 Background="White"
10 >
11
12 </Canvas>
2 xmlns="http://schemas.microsoft.com/client/2007"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 x:Name="parentCanvas"
5 Loaded="Page_Loaded"
6 x:Class="Clock.Page;assembly=ClientBin/Clock.dll"
7 Width="640"
8 Height="480"
9 Background="White"
10 >
11
12 </Canvas>
和ASP.NET中aspx页面一样,每一个元素都与.NET CLR类关联。从上面的代码我们可以看出xmlns为XML命名空间,至于有什么用处其实我也说不清,反正他自动增加的就放着吧。我们可以看到上面有一个以"x:"为前缀的属性(如果是我们自己写的就用其他前缀,和ASP.NET中自定义服务器控件注册一样),这个相当于ASP.NET中的"asp:"前缀就是注册了控件一样,也就是说以"x:"为前缀的属性在服务端可以获取,例如上面的"x:Name"在服务端就会为我们生成一个ID,我们可以通过这个ID来调用当前XAML(相当于ASP.NET服务器控件中的ID),x:Class是表示当前XAML和哪个类相关联。
我们还可以引入一个程序集,我们自己的类等等,值得注意的是Loaded这个属性的值和Page.xaml.cs中的方法是一至的,如果不一致将出现错误。OK接下来我们来看看这个例子,这个例子的最终效果图如下:
万丈高楼平地起,我们写这个程序当然也是要从底层做起,我用Blend2 May 2007打开但是不怎么会用,虽然画了图但是不知道怎么去颜色,怎么填充颜色,所以还是一步一步的建起。首先我们要画出最底层的阴影,代码如下:
1 <Ellipse
2 Height="305"
3 Width="305"
4 Fill="Black"
5 Canvas.Left="117"
6 Canvas.Top="117"
7 StrokeThickness="0"
8 Opacity="0.3"/>
2 Height="305"
3 Width="305"
4 Fill="Black"
5 Canvas.Left="117"
6 Canvas.Top="117"
7 StrokeThickness="0"
8 Opacity="0.3"/>
你可以按F5看看效果,从上面可以知道,我们画了一个宽高为305(直径)的圆,其中圆的顶端据canvas的距离是117,左边据canvas的距离也为117,不透明度为0.3。通过上面的说明大家也应该知道各个属性的用途了,这里就不多说了。我们可以看到如下效果:
接着我们通过设置StrokeThickness(厚度:我也不知道怎么说,总之是内圆和外圆半径差值)来画一个环形,然后设定两端颜色线性渐变。代码如下:
1 <Ellipse
2 Height="300"
3 Width="300"
4 Canvas.Left="115"
5 Canvas.Top="115"
6 Fill="Black"
7 StrokeThickness="20">
8 <Ellipse.Stroke>
9 <LinearGradientBrush>
10 <LinearGradientBrush.GradientStops>
11 <GradientStop Color="Red" Offset="0.1"/>
12 <GradientStop Color="Orange" Offset="0.95"/>
13 </LinearGradientBrush.GradientStops>
14 </LinearGradientBrush>
15 </Ellipse.Stroke>
16 </Ellipse>
2 Height="300"
3 Width="300"
4 Canvas.Left="115"
5 Canvas.Top="115"
6 Fill="Black"
7 StrokeThickness="20">
8 <Ellipse.Stroke>
9 <LinearGradientBrush>
10 <LinearGradientBrush.GradientStops>
11 <GradientStop Color="Red" Offset="0.1"/>
12 <GradientStop Color="Orange" Offset="0.95"/>
13 </LinearGradientBrush.GradientStops>
14 </LinearGradientBrush>
15 </Ellipse.Stroke>
16 </Ellipse>
我们可以按F5看看效果,是不是我们想象的那样,如果我猜的没有错的话Ellipse.Stroke是取得圆环部分,通过LinearGradientBrush刷子来进行填涂(不知道用什么术语),然后设置起点和终点的颜色等,效果如下:
然后我们在添加圆上的线,用黑色画圈这样显得更好看一点,以同样的原理画厚度为10的环形,在加入圆圈线等,代码如下:
1 <Ellipse Height="300" Width="300" Canvas.Left="115" Canvas.Top="115" StrokeThickness="1" Stroke="Black"/>
2
3 <Ellipse
4 Height="260"
5 Width="260"
6 Canvas.Left="135"
7 Canvas.Top="135"
8 StrokeThickness="1"
9 Stroke="Black" />
10
11 <Ellipse
12 Width="260"
13 Height="260"
14 Canvas.Left="135"
15 Canvas.Top="135"
16 StrokeThickness="10">
17 <Ellipse.Stroke>
18 <LinearGradientBrush>
19 <LinearGradientBrush.GradientStops>
20 <GradientStop Color="Green" Offset="0.05"/>
21 <GradientStop Color="Yellow" Offset="0.95"/>
22 </LinearGradientBrush.GradientStops>
23 </LinearGradientBrush>
24 </Ellipse.Stroke>
25 </Ellipse>
26
27 <Ellipse Width="260" Height="260" Stroke="Black" Canvas.Left="135" Canvas.Top="135" StrokeThickness="1"/>
28
29 <Ellipse Width="240" Height="240" Stroke="Black" Canvas.Left="145" Canvas.Top="145" StrokeThickness="1"/>
30
2
3 <Ellipse
4 Height="260"
5 Width="260"
6 Canvas.Left="135"
7 Canvas.Top="135"
8 StrokeThickness="1"
9 Stroke="Black" />
10
11 <Ellipse
12 Width="260"
13 Height="260"
14 Canvas.Left="135"
15 Canvas.Top="135"
16 StrokeThickness="10">
17 <Ellipse.Stroke>
18 <LinearGradientBrush>
19 <LinearGradientBrush.GradientStops>
20 <GradientStop Color="Green" Offset="0.05"/>
21 <GradientStop Color="Yellow" Offset="0.95"/>
22 </LinearGradientBrush.GradientStops>
23 </LinearGradientBrush>
24 </Ellipse.Stroke>
25 </Ellipse>
26
27 <Ellipse Width="260" Height="260" Stroke="Black" Canvas.Left="135" Canvas.Top="135" StrokeThickness="1"/>
28
29 <Ellipse Width="240" Height="240" Stroke="Black" Canvas.Left="145" Canvas.Top="145" StrokeThickness="1"/>
30
按F5可以看到如下效果:
现在我们所剩下的工作就是画上指针hour,minute,second。用Polygon可以画多边形,通过Points属性来确定断点坐标。我们在通过Line来画线(second), 代码如下:
1 <Polygon x:Name="Minutes"
2 Canvas.Left="265" Canvas.Top="265"
3 Points="0,0 10,-10 0,-115 -10,-10"
4 Stroke="Green" StrokeThickness="2" Opacity="0.8">
5 <Polygon.RenderTransform>
6 <RotateTransform
7 x:Name="MinutesAngle" CenterX="0" CenterY="0"/>
8 </Polygon.RenderTransform>
9 <Polygon.Fill>
10 <LinearGradientBrush>
11 <LinearGradientBrush.GradientStops>
12 <GradientStop Color="Green"
13 Offset="0.05"/>
14 <GradientStop
15 Color="Yellow" Offset="0.95"/>
16 </LinearGradientBrush.GradientStops>
17 </LinearGradientBrush>
18 </Polygon.Fill>
19 </Polygon>
20
21 <Polygon x:Name="Hours" Canvas.Left="265"
22 Canvas.Top="265" Points="0,0 10,-10 0,-90 -10,-10"
23 Stroke="Green" StrokeThickness="2" Opacity="0.8" >
24 <Polygon.RenderTransform>
25 <RotateTransform
26 x:Name="HoursAngle" CenterX="0" CenterY="0"/>
27 </Polygon.RenderTransform>
28 <Polygon.Fill>
29 <LinearGradientBrush>
30 <LinearGradientBrush.GradientStops>
31 <GradientStop Color="Green" Offset="0.05"/>
32 <GradientStop Color="Yellow" Offset="0.95"/>
33 </LinearGradientBrush.GradientStops>
34 </LinearGradientBrush>
35 </Polygon.Fill>
36 </Polygon>
37
38 <Line x:Name="Seconds" Canvas.Left="265"
39 Canvas.Top="265" X1="0" Y1="0" X2="0"
40 Y2="-120" Stroke="Red" StrokeThickness="3">
41 <Line.RenderTransform>
42 <RotateTransform
43 x:Name="SecondsAngle" CenterX="0" CenterY="0"/>
44 </Line.RenderTransform>
45 </Line>
2 Canvas.Left="265" Canvas.Top="265"
3 Points="0,0 10,-10 0,-115 -10,-10"
4 Stroke="Green" StrokeThickness="2" Opacity="0.8">
5 <Polygon.RenderTransform>
6 <RotateTransform
7 x:Name="MinutesAngle" CenterX="0" CenterY="0"/>
8 </Polygon.RenderTransform>
9 <Polygon.Fill>
10 <LinearGradientBrush>
11 <LinearGradientBrush.GradientStops>
12 <GradientStop Color="Green"
13 Offset="0.05"/>
14 <GradientStop
15 Color="Yellow" Offset="0.95"/>
16 </LinearGradientBrush.GradientStops>
17 </LinearGradientBrush>
18 </Polygon.Fill>
19 </Polygon>
20
21 <Polygon x:Name="Hours" Canvas.Left="265"
22 Canvas.Top="265" Points="0,0 10,-10 0,-90 -10,-10"
23 Stroke="Green" StrokeThickness="2" Opacity="0.8" >
24 <Polygon.RenderTransform>
25 <RotateTransform
26 x:Name="HoursAngle" CenterX="0" CenterY="0"/>
27 </Polygon.RenderTransform>
28 <Polygon.Fill>
29 <LinearGradientBrush>
30 <LinearGradientBrush.GradientStops>
31 <GradientStop Color="Green" Offset="0.05"/>
32 <GradientStop Color="Yellow" Offset="0.95"/>
33 </LinearGradientBrush.GradientStops>
34 </LinearGradientBrush>
35 </Polygon.Fill>
36 </Polygon>
37
38 <Line x:Name="Seconds" Canvas.Left="265"
39 Canvas.Top="265" X1="0" Y1="0" X2="0"
40 Y2="-120" Stroke="Red" StrokeThickness="3">
41 <Line.RenderTransform>
42 <RotateTransform
43 x:Name="SecondsAngle" CenterX="0" CenterY="0"/>
44 </Line.RenderTransform>
45 </Line>
我们可以看到效果如下:
这个是不会动的始钟,下面我们要做的是就是让时钟走起来,所以要涉及到行为等问题,我们在上面定义时钟指针时都有给他们加入x:Name属性,也就是说我们给他们一个ID。我们可以将事件绑定到指针中(事件触发器),代码如下:
1 <Canvas.Triggers>
2 <EventTrigger RoutedEvent="Canvas.Loaded">
3 <EventTrigger.Actions>
4 <BeginStoryboard>
5 <Storyboard x:Name="ClockAnimation">
6 <DoubleAnimation x:Name="SecondsAnim"
7 Storyboard.TargetName="SecondsAngle"
8 Storyboard.TargetProperty="Angle"
9 RepeatBehavior="Forever" Duration="00:01:00"/>
10 <DoubleAnimation x:Name="MinutesAnim"
11 Storyboard.TargetName="MinutesAngle"
12 Storyboard.TargetProperty="Angle"
13 RepeatBehavior="Forever" Duration="1:00:00"/>
14 <DoubleAnimation x:Name="HoursAnim"
15 Storyboard.TargetName="HoursAngle"
16 Storyboard.TargetProperty="Angle"
17 RepeatBehavior="Forever" Duration="12:00:00"/>
18 </Storyboard>
19 </BeginStoryboard>
20 </EventTrigger.Actions>
21 </EventTrigger>
22 </Canvas.Triggers>
2 <EventTrigger RoutedEvent="Canvas.Loaded">
3 <EventTrigger.Actions>
4 <BeginStoryboard>
5 <Storyboard x:Name="ClockAnimation">
6 <DoubleAnimation x:Name="SecondsAnim"
7 Storyboard.TargetName="SecondsAngle"
8 Storyboard.TargetProperty="Angle"
9 RepeatBehavior="Forever" Duration="00:01:00"/>
10 <DoubleAnimation x:Name="MinutesAnim"
11 Storyboard.TargetName="MinutesAngle"
12 Storyboard.TargetProperty="Angle"
13 RepeatBehavior="Forever" Duration="1:00:00"/>
14 <DoubleAnimation x:Name="HoursAnim"
15 Storyboard.TargetName="HoursAngle"
16 Storyboard.TargetProperty="Angle"
17 RepeatBehavior="Forever" Duration="12:00:00"/>
18 </Storyboard>
19 </BeginStoryboard>
20 </EventTrigger.Actions>
21 </EventTrigger>
22 </Canvas.Triggers>
从上述代码中我们可以知道,这个时间触发的事件由Canvas.Loaded来触发,这个对应的是<Canvas/>的Loaded属性。然后我们通过DoubleAnimation来管理各个控件,Storyboard.TargetName和刚刚画好的控件绑定,将Storyboard.TargetProperty设置为角度"Angle",永远的重复执行,就是将RepeatBehavior设置为Forever,Duration设置为什么时候是才是一圈(可能是这样,太晚了不查资料了...)。接下来要做的就是通过cs文件来控制转速,代码如下,谁都看得懂:
1 public void Page_Loaded(object o, EventArgs e)
2 {
3 // Required to initialize variables
4 InitializeComponent();
5
6 DateTime date = DateTime.Now;
7 float hourangle = (((float)date.Hour) / 12) * 360 + date.Minute / 2;
8 hourangle += 180;
9
10 float minangle = (((float)date.Minute) / 60) * 360;
11 minangle += 180;
12
13 float secangle = (((float)date.Second) / 60) * 360;
14 secangle += 180;
15
16 HoursAnim.From = hourangle;
17 HoursAnim.To = hourangle + 360;
18
19 MinutesAnim.From = minangle;
20 MinutesAnim.To = minangle + 360;
21
22 SecondsAnim.From = secangle;
23 SecondsAnim.To = secangle + 360;
24 }
2 {
3 // Required to initialize variables
4 InitializeComponent();
5
6 DateTime date = DateTime.Now;
7 float hourangle = (((float)date.Hour) / 12) * 360 + date.Minute / 2;
8 hourangle += 180;
9
10 float minangle = (((float)date.Minute) / 60) * 360;
11 minangle += 180;
12
13 float secangle = (((float)date.Second) / 60) * 360;
14 secangle += 180;
15
16 HoursAnim.From = hourangle;
17 HoursAnim.To = hourangle + 360;
18
19 MinutesAnim.From = minangle;
20 MinutesAnim.To = minangle + 360;
21
22 SecondsAnim.From = secangle;
23 SecondsAnim.To = secangle + 360;
24 }
其实只要你在控件(?应该是叫控件)用x:Name标注,在服务端的InitializeComponent(); 中就会自动为你生产如下代码:Polygon Minutes;...Minutes= this.FindName("Minutes") as Polygon;这样我们就可以直接用了,最后运行一下就OK了。这是我的第一次和SilverLight打交道,如果有什么错误的地方还请多多指教。
你可以从这里下载源代码:SourceCode
(本文的主要程序来源于:http://dotnetslackers.com/articles/silverlight/SilverlightFirstStepsAnalogClock.aspx)