SilverLight幻灯片
小弟刚刚开始学习SL,写下这篇入门,希望能抛砖引玉,与各位同学一同进步。高手请绕道。
这里将要介绍一个最简单的幻灯片程序,可以应用在Banner广告或图片播放。图片通过XML传递,配置非常方便。
在这篇文章的代码里,我将配与非常详细的注释,希望能通过代码说明SL的一些问题。
那么就开始吧,先看看最终运行效果:
首先分析下界面的元素结构:
有按钮、半透明的按钮容器、图片控件
东西不多,先从按钮说起:
在工程里创建一个UserControl,命名为TiggerButton,并在XAML中写下如下代码:
1<Grid x:Name="LayoutRoot" MouseEnter="LayoutRoot_MouseEnter" MouseLeave="LayoutRoot_MouseLeave" Cursor="Hand">
2 <Rectangle x:Name="BackGroundRec" Fill="White" RadiusY="4" RadiusX="4" Height="20" Width="45" StrokeThickness="1" Stroke="Blue" />
3 <TextBlock x:Name="tb_Number" VerticalAlignment="Center" HorizontalAlignment="Center" Text="1" FontSize="16"/>
4 </Grid>
上面代码中,最外层的Grid是自动生成的,它的作用是使得该控件中可以包含多个子元素,因为Grid继承Panel,默认属性是Children,所以可以直接把UIElement放入Grid中。在Grid中注册了MouseEnter和MouseLeave事件,这里的处理方法和Winform,ASP.NET是同出一辄的。
然后的Rectangle就是我们看见的矩形框,框四角的圆角,是由RadiusX和RadiusY指定的。StrokeThickness指定的是边框的宽度。
TextBlock的作用和我们在Winform里遇见的Label非常相似,用于输出字符串。而且Alignment属性也非常好用,直接就指定了该控件的位置,在这里由于没有指定按钮的文字,所以使用了垂直、水平居中。
1public partial class TiggerButton : UserControl
2 {
3 //依赖属性
4 public static readonly DependencyProperty NumberProperty = DependencyProperty.Register("Number",
5 typeof(int),
6 typeof(TiggerButton),
7 new PropertyMetadata(1));
8
9 public ADEntity ADE
10 {
11 get; set;
12 }
13
14 /**//// <summary>
15 /// 在按钮上显示的数字
16 /// </summary>
17 public int Number
18 {
19 get
20 {
21 return (int) GetValue(NumberProperty);
22 }
23 set
24 {
25 SetValue(NumberProperty,value);
26 tb_Number.Text = value.ToString();
27 }
28 }
29
30 /**//// <summary>
31 /// 构造函数
32 /// </summary>
33 public TiggerButton(int number,ADEntity ade):this(number)
34 {
35 ADE = ade;
36 }
37
38 /**//// <summary>
39 /// 构造函数
40 /// </summary>
41 public TiggerButton(int number):this()
42 {
43 Number = number;
44 }
45
46 public TiggerButton()
47 {
48 InitializeComponent();
49 }
50
51 private void LayoutRoot_MouseEnter ( object sender, MouseEventArgs e )
52 {
53 //设置按钮背景透明度
54 BackGroundRec.Opacity = 0.5;
55 }
56
57 private void LayoutRoot_MouseLeave ( object sender, MouseEventArgs e )
58 {
59 BackGroundRec.Opacity = 1;
60 }
61
62 /**//// <summary>
63 /// 按钮被点击后触发
64 /// </summary>
65 public event EventHandler onSelected;
66
67 private void UserControl_MouseLeftButtonDown ( object sender, MouseButtonEventArgs e )
68 {
69 if(onSelected!=null)
70 {
71 onSelected(this, null);
72 }
73 }
74 }
以上代码中,Grid的MouseEnter事件和MouseLeave事件里把矩形框的不透明度设置为0.5和1,以提示按钮被选中。
另外,在整个用户控件里,我还注册了MouseLeftButtonDown事件,并在这个事件里转发我声明的选中事件。
按钮就这样完成了。
然后在工程里创建另一个用户控件:AD,并在XAML中写下如下代码:
<!--最外层容器-->
<Grid x:Name="LayoutRoot">
<!--替换图片1-->
<Image x:Name="Image1"/>
<!--替换图片2-->
<Image x:Name="Image2"/>
<!--按钮容器-->
<Grid x:Name="ContainerGrid" VerticalAlignment="Bottom" Height="40">
<!--容器背景-->
<Rectangle Fill="Black" Opacity="0.3"/>
<!--按钮顺序容器-->
<StackPanel x:Name="ButtonContainer" Orientation="Horizontal">
</StackPanel>
</Grid>
</Grid>
上面的XAML中,描述了幻灯片的工作原理(两个图片控件不停变换透明装,并替换不同的图片),在按钮容器部分,我使用了StackPanel,就不需要对按钮的布局进行更多的控制了。
1public partial class AD : UserControl
2 {
3 /**//// <summary>
4 /// 幻灯片计时器
5 /// </summary>
6 DispatcherTimer timer;
7 /**//// <summary>
8 /// 记录当前显示的AD
9 /// </summary>
10 public ADEntity currentAD;
11 /**//// <summary>
12 /// 记录当前正在使用的Image
13 /// </summary>
14 Image currentImage;
15
16 /**//// <summary>
17 /// 当前正在显示的AD
18 /// </summary>
19 public ADEntity CurrentAD
20 {
21 get
22 {
23 return currentAD;
24 }
25 set
26 {
27 //外界可通过更改值,并显示替换图片的动态效果
28 if(!currentAD.Equals(value))
29 {
30 currentAD = value;
31 BeginAnim(value);
32 }
33 }
34 }
35
36 /**//// <summary>
37 /// AD列表
38 /// </summary>
39 List<ADEntity> ads = new List<ADEntity>();
40
41 /**//// <summary>
42 /// 构造方法
43 /// </summary>
44 public AD ( List<ADEntity> ADs )
45 : this ()
46 {
47 ads = ADs;
48 }
49
50 public AD()
51 {
52 InitializeComponent();
53 //初始化计时器
54 timer=new DispatcherTimer();
55 //计时器间隔5秒
56 timer.Interval = new TimeSpan(0,0,0,5);
57 timer.Tick += timer_Tick;
58 timer.Start ();
59 }
60
61 void timer_Tick ( object sender, EventArgs e )
62 {
63 for(int i=0;i<ads.Count;i++)
64 {
65 if(currentAD.Equals(ads[i]))
66 {
67 //在计时器中循环替换当前AD
68 CurrentAD = i==ads.Count-1 ? ads[0] : ads[i + 1];
69 break;
70 }
71 }
72 }
73
74 private void UserControl_Loaded ( object sender, RoutedEventArgs e )
75 {
76 for(int i=0;i<ads.Count;i++)
77 {
78 //加载按钮
79 TiggerButton tb = new TiggerButton(i + 1, ads[i]);
80 //按钮样式,边距为5
81 tb.Margin=new Thickness(5);
82 tb.onSelected += tb_onSelected;
83 ButtonContainer.Children.Add(tb);
84 }
85 if ( ads.Count > 0 )
86 {
87 //为当前AD赋初始值
88 currentAD = ads[0];
89 Image1.Source = new BitmapImage(new Uri(currentAD.Image, UriKind.Relative));
90 currentImage = Image1;
91 }
92 }
93
94 void tb_onSelected ( object sender, EventArgs e )
95 {
96 //按钮被选中后,替换当前AD
97 CurrentAD = ((TiggerButton) sender).ADE;
98 //重设计时器
99 timer.Start();
100 }
101
102 /**//// <summary>
103 /// 播放动画
104 /// </summary>
105 public void BeginAnim(ADEntity adEntity)
106 {
107 //构造新故事版
108 Storyboard sb_Opacity = new Storyboard();
109 //图片隐藏动画
110 DoubleAnimation ImageHideAnim = new DoubleAnimation
111 {
112 //透明度目标为0
113 To = 0,
114 //1秒动画时间
115 Duration = new TimeSpan(0, 0, 1)
116 };
117 //图片显示动画
118 DoubleAnimation ImageShowAnim = new DoubleAnimation
119 {
120 //透明度目标为1
121 To = 1,
122 //透明度初始值为0
123 From=0,
124 Duration = new TimeSpan(0, 0, 1)
125 };
126 //构造图片URI
127 Uri uri = new Uri(adEntity.Image, UriKind.Relative);
128 if(currentImage==Image1)
129 {
130 //为新图片赋值
131 Image2.Source = new BitmapImage(uri);
132 ImageHideAnim.From = Image1.Opacity;
133 //设置动画对象
134 Storyboard.SetTarget(ImageHideAnim, Image1);
135 Storyboard.SetTarget(ImageShowAnim, Image2);
136 //设置当前Image
137 currentImage = Image2;
138 }
139 else if (currentImage==Image2)
140 {
141 Image1.Source = new BitmapImage(uri);
142 ImageHideAnim.From = Image2.Opacity;
143 Storyboard.SetTarget(ImageHideAnim,Image2);
144 Storyboard.SetTarget(ImageShowAnim,Image1);
145 currentImage = Image1;
146 }
147 //设置动画对象属性
148 Storyboard.SetTargetProperty ( ImageHideAnim, new PropertyPath ( "Opacity" ) );
149 Storyboard.SetTargetProperty ( ImageShowAnim, new PropertyPath ( "Opacity" ) );
150 //把动画添加到故事版中
151 sb_Opacity.Children.Add(ImageHideAnim);
152 sb_Opacity.Children.Add(ImageShowAnim);
153 //开始动画
154 sb_Opacity.Begin();
155 }
156
157 private void UserControl_MouseEnter ( object sender, System.Windows.Input.MouseEventArgs e )
158 {
159 Storyboard sb = new Storyboard();
160 DoubleAnimation da = new DoubleAnimation()
161 {
162 Duration = new TimeSpan(0,0,1),
163 To = 1,
164 From = ContainerGrid.Opacity
165 };
166 Storyboard.SetTarget(da, ContainerGrid);
167 Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
168 sb.Children.Add(da);
169 sb.Begin();
170 }
171
172 private void UserControl_MouseLeave ( object sender, System.Windows.Input.MouseEventArgs e )
173 {
174 Storyboard sb = new Storyboard();
175 DoubleAnimation da = new DoubleAnimation
176 {
177 Duration = new TimeSpan(0,0,1),
178 To = 0,
179 From = ContainerGrid.Opacity
180 };
181 Storyboard.SetTarget(da, ContainerGrid);
182 Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
183 sb.Children.Add(da);
184 sb.Begin();
185 }
186 }
在播放动画的方法中,构造了个故事版,并把TimeLine对象添加进去。
在SL的动画中,有很多类型的TimeLine,这些TimeLine可以指定不同数据类型的变化动画。
在SetTargetProperty方法中,设置的必须是依赖属性。并且这个依赖属性必须是在后台声明的名称,类似
public static readonly DependencyProperty NumberProperty = DependencyProperty.Register("Number",
typeof(int),
typeof(TiggerButton),
new PropertyMetadata(1));
中的Number这个字符串。
XML的读取我就不再赘言了,不过要说明的是SL的运行环境中的XML对象模型,和普通的Framework对象模型完全不同,再也不能用XMLDocument之类的对象了。
这些代码可以在下面的源码中看见: