本博客已经转移至www.mozlite.com,可能不会及时更新和关注留言记录,mvc请加群88794325(已满),8781765ASP.NET(MVC)讨论二群

[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看看他们为我们做好了什么?代码如下:

 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>

    和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"/>

    你可以按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>

    我们可以按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 

    按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>

    我们可以看到效果如下:
            
    这个是不会动的始钟,下面我们要做的是就是让时钟走起来,所以要涉及到行为等问题,我们在上面定义时钟指针时都有给他们加入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>

    从上述代码中我们可以知道,这个时间触发的事件由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         }

    其实只要你在控件(?应该是叫控件)用x:Name标注,在服务端的InitializeComponent(); 中就会自动为你生产如下代码:Polygon Minutes;...Minutes= this.FindName("Minutes") as Polygon;这样我们就可以直接用了,最后运行一下就OK了。这是我的第一次和SilverLight打交道,如果有什么错误的地方还请多多指教。

你可以从这里下载源代码:SourceCode
(本文的主要程序来源于:http://dotnetslackers.com/articles/silverlight/SilverlightFirstStepsAnalogClock.aspx)

posted @ 2007-06-09 00:41  网魂小兵  Views(4339)  Comments(15Edit  收藏  举报