• [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)

  • 相关阅读:
    杨晓峰-Java核心技术-6 动态代理 反射 MD
    ARouter 路由 组件 跳转 MD
    领扣-5 最长回文子串 Longest Palindromic Substring MD
    算法 递归 迭代 动态规划 斐波那契数列 MD
    二叉树 遍历 先序 中序 后序 深度 广度 MD
    算法 数组中出现次数最多的数字 MD
    领扣-754 到达终点数字 Reach a Number MD
    领扣-1/167 两数之和 Two Sum MD
    文件 File 常见操作 工具 MD
    IO流 简介 总结 API 案例 MD
  • 原文地址:https://www.cnblogs.com/xdotnet/p/silverlight_gettingstarted_clock.html
Copyright © 2020-2023  润新知