一个非常酷的WPF的抽奖程序

 

 


头段时间为公司的年会写了个使用WPF技术的抽奖程序,实际效果很不错,就是内存占的大一些....(实际上更好的解决方案不是大批量的创建对象,而是变换固定一组对象的显示内容。)
厄,今天一时兴起,决定分享下开发这个程序的一些心得,对这个程序的代码感兴趣的朋友请到微软的MSDN Code Library下载该代码.
http://code.msdn.microsoft.com/annualfestivallotter


需求:
    1,每一个音符绑定一个抽奖号码。
    1,主持人喊开始, 一组标有数字的被打乱顺序的音符开始在波浪状的五线谱上流动,见下图。
    
    2,主持人喊结束,则在无线谱上的音符停止流动,同时从当前五线谱上的音符中随机抽取指定数量的音符,以动画的方式放大到前面,如下图。

实现机制:
   1. 实现音符
    由于整个程序需要大量的音符生成和流动,而且考虑到音符绑定了抽奖号码以及抽奖按钮按下时要执行跨越动画特效,所以特将它实现为了控件Note。
xaml代码如下:

 1 < UserControl  x:Class ="AnnualFestivalLottery.Note"
 2     xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
 4     Height ="40"  Width ="60"
 5     x:Name ="root"    
 6            
 7               >
 8      < UserControl.Resources >
 9          < Storyboard  x:Key ="Pop"  Storyboard.TargetName ="root" >
10              < DoubleAnimation  x:Name ="PopResizeX"  Storyboard.TargetName ="SizeTransform"  Storyboard.TargetProperty ="ScaleX"  To ="1.5"  Duration ="0:0:0.3" />
11              < DoubleAnimation  x:Name ="PopResizeY"  Storyboard.TargetName ="SizeTransform"  Storyboard.TargetProperty ="ScaleY"  To ="1.5"  Duration ="0:0:0.3" />
12              < DoubleAnimation  x:Name ="PopTranslateX"  Storyboard.TargetName ="Translate"  Storyboard.TargetProperty ="X" ></ DoubleAnimation >
13              < DoubleAnimation  x:Name ="PopTranslateY"  Storyboard.TargetName ="Translate"  Storyboard.TargetProperty ="Y" ></ DoubleAnimation >
14          </ Storyboard >
15      </ UserControl.Resources >
16      < UserControl.RenderTransform >
17          < TransformGroup >
18              < ScaleTransform  x:Name ="SizeTransform"    />
19              < RotateTransform  x:Name ="Rotation"   />
20              < TranslateTransform  x:Name ="Translate" />
21          </ TransformGroup >
22      </ UserControl.RenderTransform >
23      < Canvas >
24          < Image  Source ="note1.png"  x:Name ="NoteImage"  Height ="40"  Width ="30" ></ Image >
25          < TextBlock  x:Name ="NoteNumber"  Canvas.Right ="2px"  Canvas.Top ="2px"  Text =" {Binding Number,ElementName=root} "   Foreground ="White"  FontFamily ="Corbel Bold"  FontSize ="18px"   />
26      </ Canvas >
27 </ UserControl >

后端代码如下:

/**/ /// <summary>
    
/// Interaction logic for Note.xaml
    
/// </summary>

     public   partial   class  Note : UserControl
    
{
        
public event EventHandler NoteFlowCompleted;

        
private Storyboard moveNoteFlowStoryboard;
        
private Storyboard popStoryboard;

        
public Note()
        
{
            InitializeComponent();

        }


        
public Note(int number):this()
        
{
            
this.Number = number;
        }




        
public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register(
"Number"typeof(int), typeof(Note));

        
public int Number
        
{
            
get return (int)GetValue(NumberProperty); }
            
set
            
{
                SetValue(NumberProperty, value);
            }

        }


        
private void ResetNoteImage()
        
{
            
//取余处理
            int i = Number % 8;

            BitmapImage bitImg 
= new BitmapImage();
            bitImg.BeginInit();
            
switch (i)
            
{
                
case 0:
                    bitImg.UriSource 
= new Uri("note1.png", UriKind.Relative);
                    
break;
                
case 1:
                    bitImg.UriSource 
= new Uri("note2.png", UriKind.Relative);
                    
break;
                
case 2:
                    bitImg.UriSource 
= new Uri("note3.png", UriKind.Relative);
                    
break;
                
case 3:
                    bitImg.UriSource 
= new Uri("note4.png", UriKind.Relative);
                    
break;
                
case 4:
                    bitImg.UriSource 
= new Uri("note5.png", UriKind.Relative);
                    
break;
                
case 5:
                    bitImg.UriSource 
= new Uri("note6.png", UriKind.Relative);
                    
break;
                
case 6:
                    bitImg.UriSource 
= new Uri("note7.png", UriKind.Relative);
                    
break;
                
case 7:
                    bitImg.UriSource 
= new Uri("note8.png", UriKind.Relative);
                    
break;

            }

            bitImg.EndInit();
            
this.NoteImage.Stretch = Stretch.Uniform;
            
this.NoteImage.Source = bitImg;
        }



        
public void Launch(Canvas canvas, int finishX, TimeSpan floatDuration, Path path)
        
{
 
            ResetNoteImage();
            Canvas.SetLeft(
this- this.Width / 2);
            Canvas.SetTop(
this345 - this.Height / 2);

            
this.RenderTransformOrigin = new Point(0.50.5);


            DoubleAnimationUsingPath animationX 
= new DoubleAnimationUsingPath();
            animationX.PathGeometry 
= path.Data.GetFlattenedPathGeometry();
         
            animationX.Source 
= PathAnimationSource.X;
            animationX.Duration 
= new Duration(TimeSpan.FromSeconds(1.5));

            DoubleAnimationUsingPath animationY 
= new DoubleAnimationUsingPath();
            animationY.PathGeometry 
= path.Data.GetFlattenedPathGeometry();
         
            animationY.Source 
= PathAnimationSource.Y;
            animationY.Duration 
= animationX.Duration;


            moveNoteFlowStoryboard 
= new Storyboard();
            moveNoteFlowStoryboard.Children.Add(animationX);
            moveNoteFlowStoryboard.Children.Add(animationY);
            Storyboard.SetTargetName(animationX, 
"Translate");
            Storyboard.SetTargetName(animationY, 
"Translate");
            Storyboard.SetTargetProperty(animationX, 
new PropertyPath(TranslateTransform.XProperty));
            Storyboard.SetTargetProperty(animationY, 
new PropertyPath(TranslateTransform.YProperty));

            moveNoteFlowStoryboard.Completed 
+= new EventHandler(OnNoteFlowCompleted);

            moveNoteFlowStoryboard.Begin(
thistrue);


        }


        
void OnNoteFlowCompleted(object sender, EventArgs e)
        
{
            
if (NoteFlowCompleted != null)
                NoteFlowCompleted(
this, EventArgs.Empty);

        }


        
public void Pause()
        
{
            moveNoteFlowStoryboard.Pause(
this);
        }


        
/**//// <summary>
        
/// 抽奖抽中
        
/// </summary>

        public void Pop(double finishX,double finishY,TimeSpan sizeDuration,TimeSpan translateDuration)
        
{
            moveNoteFlowStoryboard.Pause(
this);

      
         
            
this.root.BorderThickness = new Thickness(1);

            
this.NoteNumber.Foreground= new SolidColorBrush(Colors.Yellow);
            Canvas.SetZIndex(
this1);
            BuildPopAnimation(finishX,finishY,sizeDuration,translateDuration);

            popStoryboard.Begin(
thistrue);

        }


        
private void BuildPopAnimation(double finishX, double finishY, TimeSpan sizeDuration, TimeSpan translateDuration)
        
{
  
            popStoryboard 
= (Storyboard)this.FindResource("Pop");
            
            
//设置变化大小的时间间隔
            ((DoubleAnimation)popStoryboard.Children[0]).Duration =  new Duration(sizeDuration);
             ((DoubleAnimation)popStoryboard.Children[
1]).Duration =  new Duration(sizeDuration);

            
//设置位置变化的时间间隔
             ((DoubleAnimation)popStoryboard.Children[2]).To = finishX;
             ((DoubleAnimation)popStoryboard.Children[
2]).Duration = new Duration(translateDuration);
             ((DoubleAnimation)popStoryboard.Children[
3]).To = finishY;
             ((DoubleAnimation)popStoryboard.Children[
3]).Duration = new Duration(translateDuration);
        }


    }

2,总执行程序
    由于需要音符在无线谱上流动,所以以一张五线谱图片作为音符流动路径背景,见下面的这段的xaml代码

  < Image  Width ="984"  Height ="492"  x:Name ="staff"  Source ="staff.png"  Stretch ="Fill"  OpacityMask =" {x:Null} "  Canvas.Left ="-0.125"  Canvas.Top ="104" />

        
< Path  x:Name ="NoteFlowPath"  StrokeThickness ="0"  Width ="976.75"  Height ="62.729"  Fill =" {x:Null} "  Stretch ="Fill"  Stroke ="#FF000000"  Canvas.Left ="2.125"  Canvas.Top ="335.293"  Data ="M1.5,1.7850879 C8.8755737,1.1145798 15.64983,1.6650583 22.5,3.0350844 22.5,3.1184142 22.5,3.201754 22.5,3.2850837 25.152671,3.2850837 27.236582,4.4100806 29.75,4.4100806 32.422817,4.4100806 34.742543,5.1570985 37.25,6.1600757 39.668691,7.127553 42.650222,6.2951653 45.125,7.2850726 47.546379,8.2536199 49.940614,9.5265863 52.625,9.9100652 52.625,9.993395 52.625,10.076735 52.625,10.160065 54.807007,10.596463 57.397165,12.167449 59.625,12.910057 62.312871,13.806014 64.891579,15.26337 67.5,15.785049 67.458333,15.826719 67.416667,15.868379 67.375,15.910048 68.119459,16.468387 69.601673,16.975715 70.375,17.285045 70.375,17.368374 70.375,17.451714 70.375,17.535044 72.05523,18.095122 73.711797,19.600188 75.375,20.285036 77.498934,21.159594 79.539657,21.881892 81.5,23.035029 83.550084,24.240955 84.907649,25.271202 87.25,25.910021 89.64477,26.563139 91.236146,26.771168 93.125,28.660013 92.833333,28.660013 92.541667,28.660013 92.25,28.660013 93.774516,28.914102 96.478945,29.79592 97.875,30.535008 99.501373,31.396025 101.20895,31.990304 103,32.660002 M102.625,32.910002 C106.15616,34.364081 109.65083,35.080356 113.25,36.160157 115.12425,36.722454 117.74375,36.596638 119.625,36.910193 121.52807,37.227389 122.96959,38.679198 124.75,39.035295 124.75,39.118629 124.75,39.201973 124.75,39.285307 127.90629,39.916597 132.54242,39.891036 135.625,41.160397 139.39029,42.710881 143.24636,41.910433 147.5,41.910433 151.50401,41.910433 155.5076,41.660421 159.5,41.660421 163.39989,41.660421 166.64869,41.360847 170.25,40.160349 170.25,40.077015 170.25,39.993671 170.25,39.910337 172.43048,39.54691 174.14509,38.081229 176.25,37.660229 176.25,37.576895 176.25,37.493551 176.25,37.410217 176.67187,37.325843 177.09887,37.198377 177.5,37.035199 M177.5,37.285 C180.58364,34.20136 184.28594,31.63304 187.75,29.035 191.89871,25.92347 194.76621,23.37758 197.375,18.16 200.26538,12.37924 200.89073,10.61178 207.375,7.91 208.99535,7.23485 210.28188,5.73243 211.5,4.7850001 212.78089,3.7887501 212.90978,2.2850001 214.875,2.2850001 214.875,2.2016701 214.875,2.1183301 214.875,2.0350001 217.36008,1.2066401 220.09958,1.0011001 222.5,-0.089999926 224.74975,-1.1126099 226.14059,-3.0166799 228.625,-3.5899999 233.8597,-4.7980099 238.85096,-5.3399999 244.375,-5.3399999 M244.125,-5.3400767 C248.85865,-6.5377517 253.71232,-6.0900798 258.875,-6.0900798 263.04803,-6.0900798 266.36546,-4.3606526 270.375,-3.2150678 273.31822,-2.3741442 278.01561,-1.6213211 280.5,0.03494585 282.10898,1.1076003 283.68285,2.1643648 285.5,2.6599568 287.33427,3.1602189 288.84687,4.1599631 290.875,4.1599631 291.43153,5.087507 295.45934,7.226686 296.75,7.9099788 298.95265,9.0760937 301.14776,10.909991 303.875,10.909991 303.875,10.993322 303.875,11.076662 303.875,11.159992 305.28113,11.159992 305.70673,11.973066 306.875,12.91 M307.125,12.91 C308.68068,14.717953 309.45042,15.821428 312,16.284987 313.20403,16.503896 314.3615,17.034984 315.625,17.034984 317.016,17.034984 317.19066,17.646731 318.375,18.534978 321.35835,20.772479 325.06917,22.725492 328.5,24.284955 331.15336,25.491021 333.81132,26.388717 336.5,27.284944 338.66085,28.005221 339.89776,29.672735 341.875,30.78493 343.62476,31.769166 345.96711,32.510253 347.5,33.659919 349.44709,35.120233 351.16911,35.708931 353.875,36.159909 355.69558,36.463338 356.80798,38.4215 358.625,38.784899 360.79225,39.218347 362.94077,40.223043 365.125,40.659892 367.14504,41.0639 369.0196,42.277085 371.125,42.659884 373.38367,43.070552 375.55376,43.435901 377.75,44.034879 382.6081,45.359813 388.10659,44.655626 393,45.784872 395.38874,46.33612 397.83965,46.624179 400.25,46.784868 402.50786,46.935387 403.95414,46.2777 406.25,46.034871 M405.875,45.910182 C410.92204,46.255874 415.7655,45.853292 420.75,44.785176 425.0293,43.86818 429.19528,42.421102 433.625,41.535157 435.51242,41.157674 437.34125,40.791902 439.25,40.41015 441.22287,40.015578 443.18287,39.349184 445.25,38.66014 448.1645,37.688634 455.29426,36.490867 457.375,34.410115 460.73659,31.048505 465.22882,31.122806 469.125,28.785082 472.33584,26.858571 475.16133,24.720528 478.75,23.28505 482.32592,21.854671 486.52127,21.297278 489.875,19.285026 491.10176,18.548972 492.52771,17.870388 493.75,16.910012 495.03194,15.902766 496.29886,15.210162 497.875,14.659999 M497.5,14.910001 C502.26881,12.483761 507.19987,9.8038007 512.25,7.9100007 515.92942,6.5302206 519.09857,4.8152906 523,4.0350006 525.97822,3.4393605 528.92304,2.8939905 531.875,1.9100005 534.16988,1.1450405 537.05507,0.92486046 538.25,-1.4649996 541.81308,-2.1776196 545.6937,-2.8198897 549.25,-4.0899997 552.5394,-5.2647797 554.71428,-6.7799298 558.125,-7.0899998 560.95009,-7.3468298 564.67544,-7.9833398 567.375,-8.9649998 570.16785,-9.9805799 573.08805,-9.9827099 576.125,-10.34 M575.75,-10.590044 C586.74339,-10.964829 597.8993,-14.068851 609.125,-12.465118 614.06995,-11.75867 619.22755,-12.544611 624,-11.590084 625.94893,-11.200278 627.59427,-11.274681 629.625,-11.090064 631.55766,-10.914357 633.38672,-10.199589 635.25,-9.4650002 M634.75,-9.0904189 C638.91925,-9.0904189 644.78901,-9.8340786 648.625,-8.090379 651.95978,-6.5745084 655.86062,-5.5570978 659.5,-4.4652342 662.88724,-3.4490236 666.65693,-2.5733087 669.875,-1.7151244 671.65704,-1.2398954 673.03956,-0.26015632 675,0.15995045 676.49264,0.47981322 678.03652,0.95437217 679.5,1.4100004 M679.125,1.6600003 C682.67354,2.5981203 686.083,5.8057505 689.5,6.6600005 691.58612,7.1815305 693.80185,6.8144705 695.875,7.1600005 698.14494,7.5383205 698.77458,7.1401805 700.625,8.7850006 703.24587,11.114661 705.11998,10.971251 708.875,11.910001 711.46847,12.558371 714.07513,14.560041 716.625,15.410001 719.29104,16.298681 722.08438,17.382921 724.375,18.910001 726.86389,20.569261 729.45885,21.430961 732.375,22.160001 735.1733,22.859581 737.67462,25.285001 740.625,25.285001 742.11335,25.285001 743.56246,26.410001 745.125,26.410001 746.94385,26.410001 747.86309,27.908012 749.375,28.160002 749.56748,28.641192 749.43363,28.544772 750.125,28.660002 750.125,28.743332 750.125,28.826672 750.125,28.910002 753.56606,29.598212 757.42002,31.156862 760.625,32.535002 M760.25,32.285002 C763.47667,34.359342 766.44219,34.123487 770.375,34.910066 773.96121,35.627323 777.53468,35.91876 781,36.785111 784.18505,37.581391 787.32449,38.660157 790.625,38.660157 793.76231,38.660157 796.64899,40.160193 799.875,40.160193 805.89479,40.160193 812.0483,42.380547 817.875,42.91026 824.13863,43.479694 830.7712,43.435963 837.25,43.160266 M837.125,43.535113 C847.13665,45.27048 856.05919,44.160119 866.375,44.160119 874.50281,44.160119 884.33379,44.872486 892.125,42.535103 894.11799,41.937197 895.81939,41.096959 897.875,40.910087 900.02661,40.714485 902.18367,40.535084 904.375,40.535084 906.30599,40.535084 908.24653,39.957108 910,39.16007 911.93997,38.278262 913.936,38.433063 916.125,38.035059 918.24948,37.648785 920.56383,37.472284 922.75,37.035049 924.8582,36.613405 926.14422,36.337933 928,35.410034 929.64136,34.589346 931.58793,34.874858 933.375,34.160021 934.75288,33.608866 937.82369,33.512625 938.5,32.160002 938.58333,32.160002 938.66667,32.160002 938.75,32.160002 938.76634,32.078281 938.71811,31.98699 938.75,31.909999 938.77255,31.855559 938.82883,31.821619 938.875,31.784998 M938.375,32.285002 C941.39974,32.104032 943.18042,30.851752 946,29.160002 946.96345,28.581932 947.50962,27.938842 948.375,27.160002 949.1769,26.438292 949.8417,26.035002 951.125,26.035002 953.29713,26.035002 954.83753,25.319372 956.75,25.160002 957.99239,25.056472 959.24318,24.786362 960.5,24.535001 961.53427,24.328151 962.93792,24.470391 963.25,22.910001 964.36294,22.724511 967.07475,20.437921 968.25,19.785001 970.04792,18.786161 971.75065,17.722181 973.625,16.785001 975.32234,15.936331 976.99546,14.405311 978.625,13.285001 980.48972,12.003001 982.46886,11.378711 984.625,10.660001 984.625,10.576671 984.625,10.493331 984.625,10.410001 984.97763,10.292461 984.93625,10.266001 985.25,10.035001"   />

上面代码中的第一部分<Image>是将五线谱图片做为背景。第二部分Path则是基于该五线谱的形状的Path路径值。
 
让音符流动的代码如下:

   /**/ /// <summary>
        
/// 运行抽奖程序
        
/// </summary>

         private   void  Run()
        
{
            
// 考虑到多个程序同时运行,所以每次运行都要重新初始化抽奖票队列

            InitializePendingTickets();


            
//洗牌
            ShuffleLotteryTickets();

            
//清理屏幕
            ClearScreen();

            
//启动音符运行动画

            
//采用Timer实现
            
//_timer = new DispatcherTimer();
            
//_timer.Interval = TimeSpan.FromSeconds(0.05);
            
//_timer.Tick += new EventHandler(delegate(object sender, EventArgs e)
            
//    {
            
//        this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new LaunchNewNoteFlowUIDelegate(LaunchNewNoteFlowUI));
            
//    }
            
//    );

            
//_timer.Start();

            
//采用Timer实现
            _timer = new Timer(new TimerCallback(this.timer_Elapsed), null050);

            _isRunning 
= true;
        }


        
private   void  ClearScreen()
        
{
            List
<Note> shouldDeleted = new List<Note>();
           
for(int i=0;i< this.canvas1.Children.Count;i++)
            
{
                Note note 
= this.canvas1.Children[i] as Note;
                
if (note != null)
                    shouldDeleted.Add(note);
            }


           
foreach (Note note in shouldDeleted)
           
{
               
this.canvas1.Children.Remove(note); 
           }

        }


        
private   void  timer_Elapsed( object  obj)
        
{
            
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new LaunchNewNoteFlowUIDelegate(LaunchNewNoteFlowUI));
        }


        
private   void  LaunchNewNoteFlowUI()
        
{
            
//超过队列最大值则归零
            if (_currentPendingTicketsTrackIndex == _pendingNumbers.Count - 1)
                _currentPendingTicketsTrackIndex 
= -1;


            LaunchNewNoteFlow(_pendingNumbers[
++_currentPendingTicketsTrackIndex]);
        }


        
/**/ /// <summary>
        
/// 启动音符
        
/// </summary>
        
/// <param name="lotteryNumber"></param>

         private   void  LaunchNewNoteFlow(Note note)
        
{
            
if (!_isRunning)
                
return;

            
//如果当前屏幕队列中已经存在准备添加的数字,则跳过
            if (CheckNumberOnScreen(note.Number))
                
return;


            
this.canvas1.Children.Add(note);
         

            note.NoteFlowCompleted 
+= new EventHandler(note_NoteFlowCompleted);
            note.Launch(
this.canvas1, (int)this.ActualWidth, TimeSpan.FromSeconds(2), this.NoteFlowPath);

        }

一开始我使用的是System.Windows.Threading.DispatcherTimer,但在实际运行中发现程序在低性能的笔记本(因为在AV台上控制,用大型投影机打到大的布幕上,所以需要笔记本)上音符流动缓慢,而且当拖动程序的界面时,音符流会有断断续续的情况,所以最后选择了System.Theading.Timer,使用System.Theading.Timer让程序在性能较低的笔记本上运行没有任何问题,看来还是cpu的时钟最可靠!

上面已经基本实现了一个在五线谱上流动的一组音符效果,但是还不够,因为随着主持人喊停,中奖的音符需要通过一段优美的动画效果放大并移动到特定的位置好让后排的观众看到中奖号码。
最的问题是如何让音符停止下来并且从当前屏幕显示的五线谱上的音符中随机选出一定数量的音符执行动画,这对我是个很严峻的挑战,一开始我考虑的是用一个队列Queue类来与在屏幕上显示的音符对应,但是实际运行起来后,发现音符从屏幕上消失的速度快于音符从队列中删除的速度,这个我一直没搞明白,虽然从队列中删除和从屏幕上删除音符的代码在一个函数中.....
    后来实在没有办法了,就把Queue干掉了,直接从页面上的控件集合中判断控件类型,取出所有的Note类型的UserControl集合。以这个集合为基础进行操作。
用户点击暂停时,代码如下:

   protected   void  PopButton_Click( object  sender, EventArgs e)
        
{
 
            
if (_isRunning)
            
{
              

                List
<Note> screenNotes = new List<Note>();

                
//停止音符的流动
                foreach (UIElement el in this.canvas1.Children)
                
{
                    Note note 
= el as Note;
                    
if (note != null)
                    
{
                        note.Pause();
                        screenNotes.Add(note);
                    }

                }


                
if (screenNotes.Count < 12)
                    
return;

                
//停止计时器
                _timer.Dispose();




                
//随机选择中奖号码

               
                List
<int> prizerIndexs = new List<int>();

                
do
                
{
                    
int prizerIndex = _random.Next(1, screenNotes.Count - 6);
                    
if (!prizerIndexs.Contains(prizerIndex))
                    
{
                        prizerIndexs.Add(prizerIndex);
                    }

                }

                
while (prizerIndexs.Count < LotterySettings.WinnersPerRun);

                List
<int> winnerNumbers = new List<int>();
                List
<Note> winnerNotes = new List<Note>();
                
foreach (int index in prizerIndexs)
                
{
                    Note note 
= screenNotes[index];
                    winnerNotes.Add(note);
                    winnerNumbers.Add(note.Number);
                }


                
//入中奖者列表数据库
                LotteryData.SaveWinnerNumbers(LotterySettings.Prize, winnerNumbers);

                BuildNotePopAnimation(winnerNotes);

                PopButton.Content 
= "继 续";
                _isRunning 
= false;
            }

            
else
            
{
                Run();
                PopButton.Content 
= "抽 奖";

            }

        }


        
/**/ /// <summary>
        
/// 创建音符跳动动画
        
/// </summary>
        
/// <param name="winnerNotes"></param>

         private   void  BuildNotePopAnimation(List < Note >  winnerNotes)
        
{
            
//创建一个虚拟的范围,在该范围内,音符按照顺序一个个的移动到指定位置
            double startX, startY;
            startX 
= (canvas1.ActualWidth / 2- 170;
            startY 
= 180;

            
int y = 0;
            
foreach (Note note in winnerNotes)
            
{
                
if (y > 0 && y % 5 == 0)
                
{
                    startX 
= (canvas1.ActualWidth / 2- 170;

                    startY 
= startY + 80;
                }


                
//指定挪动到此位置
                note.Pop(startX, startY, TimeSpan.FromSeconds(0.05), TimeSpan.FromSeconds(y * 0.05));

                
//右侧偏移10px
                startX = startX + 100;
                y
++;
            }


        }


    
对学习WPF感兴趣的朋友就到微软的MDSN Code Gallery上下载这个程序的代码吧
http://code.msdn.microsoft.com/annualfestivallotter

转载于:https://www.cnblogs.com/csharpsharper/archive/2008/03/21/annualfestivallottery.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值