Silverlight圣诞下雪动画及其扩展应用的实现

简介

前段时间看到网上有几篇关于silverlight下雪动画的文章,看过Demo之后,觉得非常有趣;于是脑海里闪现出一些想法,学习了下,并将其扩展成了以下几个有趣的web小应用.关于Silverlight下雪动画的实现方法有很多,这里有篇文章介绍的非常详细,值得一看: Falling Snow in Silverlight 

 

应用展示

这里有3个扩展的web应用 Merry Christmas, 古风歌曲页面 以及 情人节快乐!

主要用到了物体飘落的动画,加之背景图片音效,以及一些操作功能,使得一个简单的页面看起来变得更生动了些.

Merry Christmas(无音乐版)                                                                         XAP发布包(带音乐版)                          

 

 

古风歌曲页面(无音乐版)                                                                            XAP发布包(带音乐版)

 

情人节快乐! (无音乐版)                                                                             XAP发布包(带音乐版)

如有需要, 各位男生可以模仿着做个, 送给心怡的她哦  :)

 

好了,展示就到这里结束,开始我们今天的主题,实现圣诞下雪扩展应用之Merry Christmas!

 

Merry Christmas 实现

1. 创建Silverlight导航应用程序

首先,我们需要新建一个Silverlight导航应用程序,这里用到了Silverlight导航框架,主要因为它为我们定义好了页面自适应浏览器大小的框架以及页面顶端的导航控制按钮. 所以我们稍作修改就可以用了,非常方便.

01

 

Silverlight 导航应用程序主页面

 03

 

2. 添加应用程序背景

我们在MainPage.xaml页面添加一张圣诞快乐的背景图片

<!--背景图片 Begin-->
<Grid.Background>
    <ImageBrush ImageSource="Images/background_1600_900.jpg"  Stretch="Fill" />
</Grid.Background>
<!--背景图片 End-->

 

运行效果如下, 效果不错吧 :)

04 

 

3.下雪效果的实现

首先,我们需要在MainPage.xaml页面画出一些静态的雪花Ellipse.

添加一个用于装载雪花Ellipse的Canvas;

        <Canvas x:Name="CanvasLayOut" Width="1600" Height="900" >
        </Canvas>

 

然后,新建个UserControl, 名为SnowEllipse.xaml, 主要用于在Canvas内部动态添加多个Ellipse雪花,并让其运动.

<UserControl x:Class="SL_MerryChristmas.SnowEllipse"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Width="20" Height="20" >

    <Grid x:Name="LayoutRoot"  >
        <Ellipse  Fill="#FFFFFF" />
    </Grid>
</UserControl>

 

之后,在后端C#代码里实现了 设置雪花属性 以及 使其运动起来的方法.

/// <summary>
/// 设置雪花属性 
/// </summary>
/// <param name="snowAreaWidth">雪花可移动区域的宽度</param>
/// <param name="snowAreaHeight">雪花可移动区域的高度</param>
public void SetSnowEllipse(int snowAreaWidth, int snowAreaHeight)
{
    scale = randomNumber.Next(1, 15); //定义一个中间值 确保高和宽一样
    radius = randomNumber.Next(2); //雪花移动半径

    //水平和垂直方向的移动速度
    horizontalSpeed = randomNumber.NextDouble() / 50;
    verticalSpeed = randomNumber.NextDouble() * 2;

    //每个雪花的高和宽
    this.Width = scale;
    this.Height = scale;

    //透明度
    this.Opacity = 0.1 + randomNumber.NextDouble();

    SnowArea = new Point(snowAreaWidth, snowAreaHeight);

    //设置每个雪花的初始位置
    Canvas.SetLeft(this, randomNumber.Next(snowAreaWidth));
    Canvas.SetTop(this, randomNumber.Next(snowAreaHeight));

    //获取初始的移动纵坐标 
    yMovedPosition = Canvas.GetTop(this);

    //注册雪花移动方法 循环触发
    CompositionTarget.Rendering += (s, e) => { MoveSnow(); };
}

 

/// <summary>
/// 让页面上的雪花动起来
/// </summary>
public void MoveSnow()
{
    //移动过程中的位置变化
    xMovedPosition += horizontalSpeed;
    yMovedPosition += verticalSpeed;

    //设置移动状态下的雪花坐标
    Canvas.SetTop(this, yMovedPosition);
    Canvas.SetLeft(this, Canvas.GetLeft(this) + radius * Math.Cos(xMovedPosition));

    //如果雪花掉落出底部区域 则将其移回顶部
    if (Canvas.GetTop(this) > SnowArea.Y)
    {
        Canvas.SetTop(this, -30);
        yMovedPosition = Canvas.GetTop(this);
    }
    //如果水平方向超出边界 则随机移动到可见区域的某个位置
    if (Canvas.GetLeft(this) > SnowArea.X || Canvas.GetLeft(this) < 0)
    {
        Canvas.SetLeft(this, randomNumber.Next((int)SnowArea.X));
        xMovedPosition = Canvas.GetLeft(this);
    }
}

 

为了能让程序跑起来,我们需要在MainPage.xaml.cs里写点代码.  

DrawStaticSnow()方法主要用于在web页面画出静态雪花,而计时器timer则用于让静态的雪花在页面上飘起来.

SnowEllipse snowEllipse = new SnowEllipse();
private DispatcherTimer timer = new DispatcherTimer();
public MainPage()
{
    InitializeComponent();
    //画雪花
    DrawStaticSnow(200, 1600, 900);

    //让雪花动起来
    snowEllipse = new SnowEllipse();
    timer.Interval = TimeSpan.FromMilliseconds(5);
    timer.Tick += (s, e) => { snowEllipse.MoveSnow(); };
    timer.Start();
}

 

/// <summary>
/// 在页面上画出静态雪花
/// </summary>
/// <param name="count">雪花的个数</param>
/// <param name="snowAreaWidth">雪花可移动区域的宽度</param>
/// <param name="snowAreaHeight">雪花可移动区域的高度</param>
public void DrawStaticSnow(int count, int snowAreaWidth, int snowAreaHeight)
{
    for (int i = 0; i < count; ++i)
    {
        snowEllipse = new SnowEllipse();
        snowEllipse.SetSnowEllipse(snowAreaWidth, snowAreaHeight);
        CanvasLayOut.Children.Add(snowEllipse);
    }
}

 

 于是,雪花漫天飞舞的场景便做成了:)  我们运行下,看看效果.

动态下雪

 

4. 控制下雪以及增加操作提示功能

为了增加一些我们想要的功能,于是把MainPage.xaml页面顶部导航栏内容稍作修改.

右侧的两个按钮改为一个开关下雪和一个操作提示按钮

<HyperlinkButton x:Name="btnFallingSnowOrNot" Style="{StaticResource LinkStyle}" 
            Content="雪停〉_〈" />

<Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>

<HyperlinkButton x:Name="btnToolTips" Style="{StaticResource LinkStyle}" 
                Content="操作提示" />

 

针对操作提示按钮,我们还需要写个Popup控件,用于在鼠标移上去的时候弹出操作提示框,移出的时候则让提示框隐藏起来.

        <!--操作提示弹出窗口 Begin-->
        <Popup Name="ppTooltips" HorizontalAlignment="Right" Margin="0 40 140 5" IsOpen="False">
            <Border Width="140" Height="165" >
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="   鼠标右键有菜单哦" Width="140" FontSize="14" Height="20" Margin="0 3 0 0" Foreground="White" FontWeight="Bold"></TextBlock>
                    <Image Source="Images/Menu/Menu.png" Width="114" Height="130"></Image>
                </StackPanel>
            </Border>
        </Popup>
        <!--操作提示弹出窗口 End-->

 

接着,我们需要在后端实现这两个功能:

首先,在MainPage.xaml.cs的构造函数内部加入相应的鼠标事件

//给雪停 和 操作提示 两个按钮注册鼠标事件
btnFallingSnowOrNot.Click += (s, e) => { btnFallingSnowOrNot_Click(s, e); };
btnToolTips.MouseEnter += (s, e) => { btnToolTips_MouseEnter(s, e); };
btnToolTips.MouseLeave += (s, e) => { btnToolTips_MouseLevae(s, e); };

 

接着实现这些事件, 实现控制下雪事件:

/// <summary>
/// 控制下雪单击事件
/// </summary>
private void btnFallingSnowOrNot_Click(object sender, RoutedEventArgs e)
{
    if (timer.IsEnabled)
    {
        btnFallingSnowOrNot.Content = "雪下∩_∩";
        timer.Stop();
        CanvasLayOut.Children.Clear(); //移除所有的雪花颗粒
    }
    else if (!timer.IsEnabled)
    {
        btnFallingSnowOrNot.Content = "雪停〉_〈";
        DrawStaticSnow(200, 1600, 900); //重新绘制雪花颗粒
        timer.Start();
    }
}

 

实现操作提示窗体弹出和隐藏事件

/// <summary>
/// 提示窗体的弹出和隐藏事件
/// </summary>
private void btnToolTips_MouseEnter(object sender, MouseEventArgs e)
{
    if (!ppTooltips.IsOpen)
        ppTooltips.IsOpen = true;
}
private void btnToolTips_MouseLevae(object sender, MouseEventArgs e)
{
    if (ppTooltips.IsOpen)
        ppTooltips.IsOpen = false;
}

 

运行下看看

默认为下雪中

雪下

 

点击雪停,则雪停.

雪停

 

鼠标移到操作提示按钮上,弹出操作提示.

操作提示

 

移开鼠标,操作提示消失.

操作提示消失

 

5. 鼠标右键菜单

好了,最后我们需要实现的是一个鼠标右键菜单.

实现前,我们需要先给页面添加一首背景音乐,让页面看起来更动感;在MainPage.xaml.cs构造函数内部加入如下代码.

//添加背景音乐
backgroundMusic.Source = new Uri("/We Wish You A Merry Christmas.mp3", UriKind.RelativeOrAbsolute);
backgroundMusic.AutoPlay = true;
LayoutRoot.Children.Add(backgroundMusic);

这样当我们运行的时候 就能听到美妙动听的背景音乐了 :)

 

接着是制作鼠标右键菜单:

这里,我们需要先添加一个System.Windows.Controls.Input.Toolkit dll的引用.

如果添加引用里没有的话可以去这里下载 http://silverlight.codeplex.com/releases/view/43528/ 

添加Toolkit引用

 

然后在MainPage.xaml里引用它

xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"

 

并添加右键菜单的XAML代码,右键菜单包含了刷新页面,开关背景音乐,全屏观看以及关闭页面4个方法.

        <!--右键菜单 Begin-->
        <my:ContextMenuService.ContextMenu>
            <my:ContextMenu FontSize="14" FontStyle="Normal"  Foreground="#0087CB"  BorderBrush="#0087CB" BorderThickness="2" >
                <my:MenuItem  Header="刷新" ToolTipService.ToolTip="刷新页面" Click="MenuItem_Click">
                    <my:MenuItem.Icon>
                        <Image Source="Images/Menu/Refresh_blue.png"/>
                    </my:MenuItem.Icon>
                </my:MenuItem>
                <my:Separator/>

                <my:MenuItem x:Name="itemCloseMusic" Header="关闭音乐" ToolTipService.ToolTip="关闭背景音乐" Click="MenuItem_Click">
                    <my:MenuItem.Icon>
                        <Image x:Name="imgPlay" Source="Images/Menu/Player Stop_blue.png"  Width="16" Height="16" />
                    </my:MenuItem.Icon>
                </my:MenuItem>
                <my:Separator/>

                <my:MenuItem x:Name="itemFullScreen" Header="全屏模式" ToolTipService.ToolTip="启动全屏模式" Click="MenuItem_Click">
                    <my:MenuItem.Icon>
                        <Image Source="Images/Menu/Full Size_blue.png" Width="16" Height="16" />
                    </my:MenuItem.Icon>
                </my:MenuItem>
                <my:Separator/>

                <my:MenuItem  Header="关闭"  ToolTipService.ToolTip="关闭当前页面" Click="MenuItem_Click">
                    <my:MenuItem.Icon>
                        <Image Source="Images/Menu/Exit_blue.png" Width="16" Height="16" />
                    </my:MenuItem.Icon>
                </my:MenuItem>

            </my:ContextMenu>
        </my:ContextMenuService.ContextMenu>
        <!--右键菜单 End-->

 

之后,在后端相应的菜单按钮事件下,实现这些方法.

这里需要增加一个Menu类,里面包含了全屏,关闭当前页面,刷新3个方法.

public class Menu
{
    public static string FullScreen(string screenState)
    {
        if (screenState == "全屏模式")
            screenState = "退出全屏";
        else
            screenState = "全屏模式";
        if (!Application.Current.Host.Content.IsFullScreen)
            Application.Current.Host.Content.IsFullScreen = true;
        else
            Application.Current.Host.Content.IsFullScreen = false;
        return screenState;
    }

    public static void Exit()
    {
        if (MessageBox.Show("确认关闭当前页面?(仅在IE下有效)", "退出提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
        {
            System.Windows.Browser.HtmlPage.Window.Invoke("close");
        }
    }

    public static void Refresh(Frame frame)
    {
        frame.Refresh();
    }
}

 

最后是实现我们的右键菜单的单击事件了

        /// <summary>
        /// 鼠标右键菜单
        /// </summary>
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = sender as MenuItem;
            switch (menuItem.Header.ToString())
            {
                case "刷新":
                    timer.Stop();
                    CanvasLayOut.Children.Clear();
                    DrawStaticSnow(200, 1600, 900); //重新绘制雪花颗粒
                    timer.Start();
                    backgroundMusic.Stop();
                    backgroundMusic.Play();
                    break;

                case "关闭音乐":
                    backgroundMusic.Stop();
                    menuItem.Header = "开启音乐";
                    ToolTipService.SetToolTip(menuItem, "开启背景音乐");
                    Uri uriPlay = new Uri("Images/Menu/Player Play_blue.png", UriKind.RelativeOrAbsolute);
                    BitmapImage bitImg = new BitmapImage(uriPlay);
                    imgPlay.Source = bitImg;
                    break;

                case "开启音乐":
                    backgroundMusic.Play();
                    menuItem.Header = "关闭音乐";
                    ToolTipService.SetToolTip(menuItem, "关闭背景音乐");
                    Uri uriStop = new Uri("Images/Menu/Player Stop_blue.png", UriKind.RelativeOrAbsolute);
                    BitmapImage bitImg2 = new BitmapImage(uriStop);
                    imgPlay.Source = bitImg2;
                    break;

                case "全屏模式":
                    menuItem.Header = Menu.FullScreen(menuItem.Header.ToString());
                    ToolTipService.SetToolTip(menuItem, "退出全屏模式");
                    break;

                case "退出全屏":
                    menuItem.Header = Menu.FullScreen(menuItem.Header.ToString());
                    ToolTipService.SetToolTip(menuItem, "启动全屏模式");
                    break;

                case "关闭":
                    Menu.Exit();
                    break;

                default:
                    break;
            }
        }

 

运行看下

右键菜单

 

到这里整个下雪的扩展小应用Merry Christmas便完成了 :)     Merry Christmas源代码下载

posted @ 2013-03-21 21:41  SilverSky(Jason)  阅读(3091)  评论(15编辑  收藏  举报