这里我们一起来制作一个Silverlight轮盘图片展示程序,效果如下图:
我们要实现的功能包括:
1、通过图片数量滑条来改变轮盘中图片的数目
2、通过图片X轴与Y轴半径滑条来改变轮盘的X轴方向与Y轴方向的大小
3、通过Auospin按钮来让轮盘自动转动,且其转动速度取决于鼠标距离程序背景中线的距离
4、通过Reset按钮让轮盘恢复初始设置
5、通过按下鼠标左键手工让轮盘转动,且其转动速度取决于鼠标距离程序背景中线的距离
,释放鼠标左键让轮盘停止转动。
6、点击轮盘图片时就在放映区显示此图片的大图
下面我们来创建我们的程序。
打开Vs2008,新建项目,创建一个名为SLImageCarousel的Silverlight应用程序,然后在SilverlightApplication1项目上新建一个名为images的文件夹,请拷贝二三十张图片到此文件夹下,分别改名字从0.jpg,1.jpg,......n.jpg,另外再拷贝一张图片1.jpg到外面,程序如下图:
一、界面代码如下(Page.xaml文件):
Code
<UserControl x:Class="SilverlightApplication1.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="1024" Height="768">
<Canvas x:Name="root" Canvas.Top="200" Width="1024" Height="768" MouseLeftButtonDown="MainContactDown" MouseLeftButtonUp="MainContactUp" MouseMove="root_MouseMove">
<Rectangle Width="1024" Height="768" >
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="0.5,0" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5">
<GradientStop Color="Beige" Offset="0" />
<GradientStop Color="Blue" Offset="1" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Image Name="mainImage" Canvas.Left="270" Canvas.Top="60" Canvas.ZIndex="169" Stretch="Fill" Height="290" Width="480" Source="1.jpg"/>
<Canvas Canvas.Left="270" Canvas.Top="350" >
<Canvas Canvas.Top="290">
<Canvas.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0.43" Color="BlanchedAlmond"/>
<GradientStop Offset="0.8" Color="Green"/>
</LinearGradientBrush>
</Canvas.OpacityMask>
<Image Name="mainImageReflection" Canvas.Left="-8" Canvas.Top="-338" Source="1.jpg"
Stretch="Fill" Height="380" Width="480" Opacity="0.4" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="-0.75"></ScaleTransform>
<SkewTransform AngleX="-15"></SkewTransform>
<TranslateTransform Y="-1" X="-30"></TranslateTransform>
</TransformGroup>
</Image.RenderTransform>
<Image.OpacityMask>
<LinearGradientBrush StartPoint="0.5,0.0" EndPoint="0.5,1.0">
<GradientStop Offset="0.0" Color="#00000000" />
<GradientStop Offset="1.0" Color="#FF000000" />
</LinearGradientBrush>
</Image.OpacityMask>
</Image>
</Canvas>
</Canvas>
<!--以下是定义控制面板-->
<Rectangle Width="1024" Height="68" Canvas.Top="700" Opacity="0.5">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#888" Offset="0" />
<GradientStop Color="#222" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock Text="图片数量" FontSize="12" Canvas.Top="720" Canvas.Left="30" Foreground="White"/>
<Slider Value="40" ValueChanged="numPhotosSliderChanged" x:Name="numPhotosSlider" Canvas.Left="100" Canvas.Top="720" Width="200"/>
<TextBlock Text="调整转盘横向半径" FontSize="12" Canvas.Top="720" Canvas.Left="600" Foreground="White"/>
<Slider Value="500" ValueChanged="radiusSliderChangedX" x:Name="radiusSliderX" Canvas.Left="700" Canvas.Top="720" Width="200"/>
<TextBlock Text="调整转盘纵向半径" FontSize="12" Canvas.Top="740" Canvas.Left="600" Foreground="White"/>
<Slider Value="500" ValueChanged="radiusSliderChangedY" x:Name="radiusSliderY" Canvas.Left="700" Canvas.Top="740" Width="200"/>
<Button x:Name="ResetImagesButton" Click="ResetImagesButton_Click" Canvas.Top="740" Canvas.Left="460" Width="70" Content="Reset"/>
<Button x:Name="AutoSpinButton" Click="AutoSpinButton_Click" Canvas.Top="710" Canvas.Left="460" Width="70" Content="AutoSpin"/>
</Canvas>
</UserControl>
二、程序后台代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading; //因为要用到DispatcherTimer等
using System.Windows.Media.Imaging; //因为要用到BitmapImage
using System.Diagnostics; //因为要用到Debug
namespace SilverlightApplication1
{
public partial class Page : UserControl
{
定义变量#region 定义变量
private Boolean page_loaded = false;
List<object> angleValues = new List<object>(); //转盘图片在转盘中的角度位置
private int num_images = 20; //当前图片数量,初始化成20
private int radiusX = 500; //设置椭圆的长半径
private int radiusY = 110; //设置椭圆的短半径
private int centerX = 460; //设置椭圆的X坐标
private int centerY = 260; //设置椭圆的Y坐标
private double speed = 0;
private DispatcherTimer myTimer;
private bool main_down = false;
private DispatcherTimer autoTimer = new DispatcherTimer();
#endregion
定义要调用的函数#region 定义要调用的函数
Page_Load事件#region Page_Load事件
void Page_Loaded(object sender, RoutedEventArgs e)
{
myTimer.Start();
//加载默认初始照片
Uri uri = new Uri("./images/0.jpg", UriKind.Relative);
ImageSource imgSource = new BitmapImage(uri);
mainImage.Source = imgSource;
mainImageReflection.Source = imgSource;
//Debug.WriteLine("Loaded: " + mainImage.Source);
page_loaded = true; //设置page_loaded标志,表明已经加载了图片了
}
#endregion
Canvas_MouseLeftButtonDown事件#region Canvas_MouseLeftButtonDown事件
void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Canvas c = sender as Canvas;
//c.Opacity = 0.5;
Rectangle r = c.Children[0] as Rectangle; //取得边框
Image img = c.Children[1] as Image; //取得图片
img.Opacity = 0.3; //设置图片透明度
//Debug.WriteLine("canvas down");
//加载点击选中的图片
mainImage.Source = img.Source;
mainImageReflection.Source = img.Source;
//设置边框颜色
r.Stroke = new SolidColorBrush(Colors.Red);
}
#endregion
清除所有图片#region 清除所有图片
void RemoveImages()
{
angleValues = new List<object>(); //重新new一个angleValues
for (int i = 0; i < num_images; i++) //移除所有图片
{
Canvas c = this.FindName("imageHolder_" + i) as Canvas;
if (c != null)
{
root.Children.Remove(c);
}
}
}
#endregion
加载指定数量的图片#region 加载指定数量的图片
private void BuildImages()
{
int cnt = 0; //计数
for (int i = 0; i < num_images; i++)
{
放置图片的Canvas创建与设置#region 放置图片的Canvas创建与设置
Canvas c = new Canvas();
c.Name = "imageHolder_" + i;
c.Width = 100;
c.Height = 100;
//Microsoft.Surface.Presentation.Contacts.AddPreviewContactDownHandler(c, CanvasImage_PreviewContactDown);
c.MouseLeftButtonDown += new MouseButtonEventHandler(Canvas_MouseLeftButtonDown); //加载鼠标点击事件
#endregion
图片的边框创建与设置#region 图片的边框创建与设置
创建一个边框#region 创建一个边框
Rectangle r = new Rectangle();
r.Width = 100;
r.Height = 100;
#endregion
边框填充方法一:直接填充图片所在的边框#region 边框填充方法一:直接填充图片所在的边框
// r.Fill = new SolidColorBrush(Colors.Orange);
#endregion
边框填充方法二:手工创建一个Brush,并使用此Brush来填充图片所在的边框#region 边框填充方法二:手工创建一个Brush,并使用此Brush来填充图片所在的边框
//创建一个Brush
LinearGradientBrush myLGB = new LinearGradientBrush();
myLGB.StartPoint = new Point(0, 0);
myLGB.EndPoint = new Point(0, 1);
GradientStop gs1 = new GradientStop();
gs1.Color = Colors.White;
gs1.Offset = 0.0;
GradientStop gs2 = new GradientStop();
gs2.Color = Colors.Gray;
gs2.Offset = 1.0;
myLGB.GradientStops.Add(gs1);
myLGB.GradientStops.Add(gs2);
//使用上面创建的Brush来填充图片所在的边框
r.Fill = myLGB;
#endregion
r.Stroke = new SolidColorBrush(Colors.Gray);
#endregion
图片控件创建与设置#region 图片控件创建与设置
//创建一个图片控件
Image img = new Image();
img.Stretch = Stretch.Fill;
img.Width = 80;
img.Height = 80;
img.SetValue(Canvas.LeftProperty, 10.0);
img.SetValue(Canvas.TopProperty, 10.0);
//创建一个图片源对象
Uri uri = new Uri("./images/" + cnt + ".jpg", UriKind.Relative);
ImageSource imgSource = new BitmapImage(uri);
//如果图片小于20张,则重复使用
if (cnt < 20)
{
cnt++;
}
else
{
cnt = 0;
}
img.Source = imgSource;
#endregion
在上面创建的Canvas中添加创建的边框和图片控件#region 在上面创建的Canvas中添加创建的边框和图片控件
c.Children.Add(r);
c.Children.Add(img);
#endregion
设置图片缩放比例#region 设置图片缩放比例
ScaleTransform st = new ScaleTransform();
st.CenterX = 50;
st.CenterY = 50;
st.ScaleX = 1;
st.ScaleY = 1;
c.RenderTransform = st;
#endregion
图片角度位置的计算与保存#region 图片角度位置的计算与保存
double ang = (double)i * ((Math.PI * 2) / num_images); //取得对应位置的角度值
angleValues.Add(ang); //把角度值保存到List中
#endregion
把上面创建的Canvas添加到页面上#region 把上面创建的Canvas添加到页面上
// c.SetValue(Canvas.LeftProperty, i * 100.0);
root.Children.Add(c);
#endregion
}
PositionImagesInCircle(); //放置对应的图片
}
#endregion
设置各个转盘图片在转盘中的位置以及缩放比例#region 设置各个转盘图片在转盘中的位置以及缩放比例
private void PositionImagesInCircle()
{
for (int i = 0; i < num_images; i++) //遍历所有指定数量的图片
{
//根据角度确定椭圆轨迹上的坐标值
double my_x = (double)Math.Cos((double)angleValues[i]) * radiusX + centerX; //取得X轴坐标值
double my_y = (double)Math.Sin((double)angleValues[i]) * radiusY + centerY; //取得Y轴坐标值
Canvas c = root.FindName("imageHolder_" + i) as Canvas; //找到子图片所在Canvas
c.SetValue(Canvas.LeftProperty, my_x); //设置Canvas的坐标值
c.SetValue(Canvas.TopProperty, my_y);
c.SetValue(Canvas.ZIndexProperty, (int)my_y); //设置Canvas的显示层次值,在Y坐标上值大图片的覆盖值小的图片
//缩放变换ScaleTransform允许我们对元素进行缩放,通过属性ScaleX和ScaleY来分别指定在X轴和Y轴上的缩放比例,
//同样也可以使用属性CenterX和CenterY来指定缩放中心
ScaleTransform st = c.RenderTransform as ScaleTransform;
double my_scale = (my_y - st.ScaleY) / (centerY + radiusY - st.ScaleY); //按一定方式进行缩放,原则是Y轴值大的图片大,Y轴值小的图片小
//double my_scale = (my_x - st.ScaleX) / (centerX + radiusX - st.ScaleX); //另外一种缩放公式
//double my_scale = 2 + (double)Math.Cos((double)angleValues[i] - Math.PI / 2); //另外一种缩放公式
st.ScaleX = my_scale;
st.ScaleY = my_scale;
angleValues[i] = (double)angleValues[i] + speed;
}
}
#endregion
myTimer_Tick 事件处理函数#region myTimer_Tick 事件处理函数
void myTimer_Tick(object sender, EventArgs e)
{
if (main_down)
{
PositionImagesInCircle(); //调整图片位置与缩放比例
}
}
#endregion
#endregion
public Page()
{
InitializeComponent();
ResetImagesButton.Click += new RoutedEventHandler(ResetImagesButton_Click); //按下Reset按钮时做ResetImagesButton_Click操作
myTimer = new DispatcherTimer();
myTimer.Interval = TimeSpan.FromMilliseconds(33);
myTimer.Tick += new EventHandler(myTimer_Tick);
//Console.WriteLine("call start");
//设置数量控制滑条的最大值与最小值
numPhotosSlider.Maximum = 180;
numPhotosSlider.Minimum = 10;
//设置X半径控制滑条的最大值与最小值
radiusSliderX.Maximum = 500;
radiusSliderX.Minimum = 320;
//设置Y半径控制滑条的最大值与最小值
radiusSliderY.Maximum = 200;
radiusSliderY.Minimum = 100;
Loaded += new RoutedEventHandler(Page_Loaded);
BuildImages();
}
private void numPhotosSliderChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Slider s = sender as Slider;
if (page_loaded) //如果页面已经加载
{
RemoveImages(); //移除所有图片
num_images = (int)s.Value; //重新设置当前应该加载的图片数量
BuildImages(); //重新加载图片
}
}
private void ResetImagesButton_Click(object sender, RoutedEventArgs e)
{
RemoveImages(); //清除所有图片
恢复变量默认初始值#region 恢复变量默认初始值
num_images = 20;
radiusX = 500;
radiusY = 110;
centerX = 460;
centerY = 260;
mainImage.SetValue(Canvas.ZIndexProperty, 169);
#endregion
BuildImages(); //重新加载指定数量的图片
重新设置滑条默认值#region 重新设置滑条默认值
numPhotosSlider.Value = 40.0;
radiusSliderX.Value = 500;
radiusSliderY.Value = 1100;
#endregion
}
private void radiusSliderChangedX(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Slider s = sender as Slider;
if (page_loaded) //如果页面已经成功加载则作后续处理
{
RemoveImages(); //移除所有图片
radiusX = (int)s.Value; //取得新的半径值
if (s.Value < 450) //如果新的半径值低于我们要求的上限,则作调整,否则不作变动
{
//调整mainImage控件的ZIndexProperty属性,以免它因为radius的变动被后面的图片轮挡住
int z = (int)mainImage.GetValue(Canvas.ZIndexProperty);
z += 2;
mainImage.SetValue(Canvas.ZIndexProperty, z);
}
else
{
mainImage.SetValue(Canvas.ZIndexProperty, 169);
}
BuildImages(); //重新加载图片
}
}
private void MainContactDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(this);
Debug.WriteLine(">>" + p.Y);
if (p.Y > 500 && p.Y < 650) //判断是否在指定的区域内按下了鼠标
{
main_down = true;
}
}
private void MainContactUp(object sender, MouseButtonEventArgs e)
{
main_down = false;
}
private void root_MouseMove(object sender, MouseEventArgs e)
{
Point p = e.GetPosition(this);
speed = ((p.X - 500) / 500) * 0.0755; //调整轮盘的转速
//Debug.WriteLine("changed: " + speed);
}
private void radiusSliderChangedY(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Slider s = sender as Slider;
if (page_loaded) //如果页面已经成功加载则作后续处理
{
RemoveImages(); //移除所有图片
radiusY = (int)s.Value; //取得新的半径值
if (s.Value < 200) //如果新的半径值低于我们要求的上限,则作调整,否则不作变动
{
//调整mainImage控件的ZIndexProperty属性,以免它因为radius的变动被后面的图片轮挡住
int z = (int)mainImage.GetValue(Canvas.ZIndexProperty);
z += 2;
mainImage.SetValue(Canvas.ZIndexProperty, z);
}
else
{
mainImage.SetValue(Canvas.ZIndexProperty, 169);
}
BuildImages(); //重新加载图片
}
}
autoTimer_Tick 事件处理函数#region autoTimer_Tick 事件处理函数
void autoTimer_Tick(object sender, EventArgs e)
{
PositionImagesInCircle(); //调整图片位置与缩放比例
}
#endregion
private void AutoSpinButton_Click(object sender, RoutedEventArgs e)
{
autoTimer.Start();
autoTimer.Interval = TimeSpan.FromMilliseconds(33);
autoTimer.Tick += new EventHandler(autoTimer_Tick);
}
}
}
代码说明:
1、关于轮盘上图片位置的确定
根据以下的椭圆图
在椭圆 (x2 /a)+(y2 /b ) =1 中,令 x/a=cosθ, y/b=sinθ 得 x=a cos θ y=b sin θ,这就是椭圆的参数方程,其中θ为参数(注意:θ 的几何意义是椭圆上点P对应的参数θ 应是∠AOx ,而不是 ∠POx);而 a 为椭圆的外切圆半径,b为椭圆的内切圆半径。
当我们确定椭圆轨道上放置N张图片时,我们可以计算得到图片间的夹角 θ= 360/N。此图这个椭圆正好在坐标中心,而在程序中,它可能位于于坐标(x,y)处。所以我们代码实现如下:
取得夹角
#region 图片角度位置的计算与保存
double ang = (double)i * ((Math.PI * 2) / num_images); //取得对应位置的角度值
angleValues.Add(ang); //把角度值保存到List中
#endregion
取得坐标
//根据角度确定椭圆轨迹上的坐标值
double my_x = (double)Math.Cos((double)angleValues[i]) * radiusX + centerX; //取得X轴坐标值
double my_y = (double)Math.Sin((double)angleValues[i]) * radiusY + centerY; //取得Y轴坐标值
2、关于图片大小
为了产生轨道上离我们近的图片大,离我们远的图片小的效果,我们需要根据图片放置的位置调整图片显示的大小,我们用以下方式来实现此目的
//缩放变换ScaleTransform允许我们对元素进行缩放,通过属性ScaleX和ScaleY来分别指定在X轴和Y轴上的缩放比例,
//同样也可以使用属性CenterX和CenterY来指定缩放中心
ScaleTransform st = c.RenderTransform as ScaleTransform;
double my_scale = (my_y - st.ScaleY) / (centerY + radiusY - st.ScaleY); //按一定方式进行缩放,原则是Y轴值大的图片大,Y轴值小的图片小
//double my_scale = (my_x - st.ScaleX) / (centerX + radiusX - st.ScaleX); //另外一种缩放公式
//double my_scale = 2 + (double)Math.Cos((double)angleValues[i] - Math.PI / 2); //另外一种缩放公式
st.ScaleX = my_scale;
st.ScaleY = my_scale;
3、关于轮盘转速
我们有个Speed参数来调整轮盘旋转速度,实现思路是根据鼠标当前位置相对于轮盘Y轴的相对位置来调整,实现代码如下:
Point p = e.GetPosition(this);
speed = ((p.X - 500) / 500) * 0.0755; //调整轮盘的转速
运行程序即可看到效果
本文程序在Silverlight2.0和VS2008环境中调试通过。本文参照了部分网络资料,希望能够抛砖引玉,大家共同学习。
(转载本文请注明出处)前往:Silverlight学习笔记清单