这个导航栏简洁明快,主体透明,将底图的蓝色背景显现出来,并且模仿很多以div+css布局的网站,将它做得很有TopNav的味道(横向导航一般也是用ul+li并且配合display:inline来将一个本来纵向分布的列表变成水平导航栏,具体实现可以去网上查阅,我在这里就不多讲了)。
本来很想将这个silverlight程序的xap下载下来研究一下,不过我却发现它是用js做的,也许是从silverlight1.0开始就没有换过的原因,也许是考虑到兼容性的问题,总之它不是用我熟悉的
xaml+cs写的,而js我几乎没有学过……
毛主席讲过,自己动手丰衣足食,我们也不能总寄希望于别人的成果,虽然微软的工程师们想让程序员变得越来越白痴,但是我们自己还不想过早得变成白痴。所以我决定,自己依照silverlight官网那个导航栏,自己做一个,当然是要用c#写啦。
下面,开始step-by-step:
1)这个程序要做成透明的,不多说,改两个地方
a.在page.xaml文件中,改为Grid x:Name="LayoutRoot" Background="Transparent"
b.在test.html文件中的<object>标签下,加上两句<param name="background" value="Transparent" /><param name="windowless" value="true" />
2)参照上图,对应用做一下整体的步局,大致分成三块,最上面是导航文字,中间跑那个动画,最下面显示description,第一块分成六格,每格宽度100,布局是用Grid进行的,原理很简单,由于代码很多,我就不贴上来了,大家可以去源代码里看。
3)用<TextBlock>标签显示文字,用<Line>标签显示文字间的竖线,并修改文字大小、颜色、字体、对齐等属性,这段是力气活,没有技术含量
4)设计动画:
1 <Canvas x:Name="middle" Grid.Row="1">
2 <Canvas.Resources>
3 <Storyboard x:Name="focus">
4 <DoubleAnimation x:Name="moveX" Storyboard.TargetName="move" Storyboard.TargetProperty="(Canvas.Left)" AutoReverse="False" RepeatBehavior="1x" Duration="0:0:0.4"/>
5 </Storyboard>
6 </Canvas.Resources>
7 <Line X1="0" Y1="10" X2="600" Y2="10" Stroke="White"/>
8 <Canvas x:Name="move" Width="100" Canvas.Top="0">
9 <Line X1="15" Y1="10" X2="85" Y2="10" Stroke="White"/>
10 <Polygon Stroke="White" Points="50,5 46.5,10 53.5,10" Fill="White"/>
11 </Canvas>
12 </Canvas>
a.首先在名为move的Canvas内画上一条直线和一个三角形,用于指示当前选择的导航
b.创建一个动画,用以改变这个Canvas对于它的父容器(Canvas)的Canvas。Left属性,From和To两个属性将在代码中进行动态的设定
5)设计Description并为其应用动画
1 <StackPanel x:Name="descriptionPanel" Orientation="Horizontal" Grid.Row="2">
2 <StackPanel.Resources>
3 <Storyboard x:Name="description_appear">
4 <DoubleAnimation x:Name="description_appearAnimation" Storyboard.TargetName="descriptionPanel" Storyboard.TargetProperty="Opacity" From="0" To="1.0" Duration="0:0:0.2" AutoReverse="False" RepeatBehavior="1x"/>
5 </Storyboard>
6 <Storyboard x:Name="description_disappear" Completed="description_disappear_Completed">
7 <DoubleAnimation x:Name="description_disappearAnimation" Storyboard.TargetName="descriptionPanel" Storyboard.TargetProperty="Opacity" From="1.0" To="0" Duration="0:0:0.2" AutoReverse="False" RepeatBehavior="1x"/>
8 </Storyboard>
9 </StackPanel.Resources>
10 <Rectangle x:Name="imageContainer" Width="24" Height="24"/>
11 <TextBlock x:Name="descriptionTextBlock" Foreground="White" FontFamily="Verdana" FontSize="10" Margin="10 10 0 5"/>
12 </StackPanel>
a.设计一个矩形,用以显示示意图片,还有一个TextBlock用以显示描述的文字
b.设计两个动画,一个是消失的,一个是出现的,为了展示淡入淡出的效果,应用的是很常用的针对透明度的渐变动画
以上五个步骤之后,xaml搞一段落,下面就要在Behind Code上下功夫了。
说起来后台的事件响应代码,并不是多么的复杂,无非是为每个Canvas的MouseEnter、MouseLeave和MouseLeftButtonDown编写处理函数,不过有一个地方,是稍微有一点技术含量的。这是因为在silverlight官网那个导航的设计上,有一个当用户不操作时,自动切换当前选中的导航并且显示description的机制,因此为了模拟这个,我用到了多线程。
在初始化的时候,我就让那个线程开始运行并且无限循环,当用户失去对导航的控制的时候,它就将每隔一定的时间自动切换导航。
线程的处理委托如下:
1 private void AutoGetFocus(object o)
2 {
3 while (true)
4 {
5 if (!humanControl)
6 {
7 Dispatcher.BeginInvoke(delegate
8 {
9 if (Choice[(Selecting + 1) % 6] == Selected)
10 {
11 Selecting = Choice[(Selecting + 2) % 6];
12 }
13 else
14 {
15 Selecting = Choice[(Selecting + 1) % 6];
16 }
17 });
18 }
19 Thread.Sleep(4000);
20 }
21 }
需要一提的是,由于改变属性Selecting将会改变UI,因此需要用到Dispatcher.BeginInvoke方法,不然在运行时是会出现异常的。另外,我想应该会有一种方法可以让这个自动改变选中导航用动画的形式实现,但是经过尝试我发现还不如用一个线程做起来方便,于是就没有那么做。还有,这个程序要求在导航到的每一个页面相同的位置放入这个silverlight控件以保证显示正常,我想可以通过cookie、session甚至Htmo Dom Tag的方式通知silverlight程序,在它初始化Selected的时候,根据当前页面的不同进行不同的选择(在我的代码里是写死了的,主要是我懒得去做那么多页面测试了^_^)。
最后我给出项目的源代码和它的开发环
境:
开发:Visual Studio2008Sp1 浏览器:Internet Explorer7.0 Silverlight版本:Silverlight 2Beta2 操作系统:windows Vista Home Basic Sp1
截图留念:
PS:我没去截silverlight官网上那几张示意图片,就用了几张Dota的图代替了,希望不会影响大家心情。
本文作者:未知