找回密码
 立即注册
首页 业界区 业界 Silverlight 3 ShowCase(1)- 3D图片走马灯

Silverlight 3 ShowCase(1)- 3D图片走马灯

莅耸 2025-5-30 01:06:28
前提条件:

  阅读本文之前请确认你已经安装了如下软件
  
          
  • Visual Studio 2008 (Express) SP1   
  • Silverlight 3 Tools For Visual Studio   
  • Microsoft Expression Blend 3 MIX 09 Preview
  ShowCase一瞥:

  本文的ShowCase是一个3D的图片走马灯程序
  图片的来源是来自Flickr图片共享网站
  大家可以通过搜索关键字来获取得到8张图片
  在线Demo
  
  效果图
  
1.png

  关键代码:

  本文的图片来自Flickr,为了获取得到图片
  我们需要了解下Flickr Service API
  在这里采用flickr.photos.search这个接口来搜索并获取图片
  
2.png

  于是我们就有了我们搜索的图片的Rest Url了
         
  1. private string SearchFormattedUrl = "http://api.flickr.com/services/rest/?method=flickr.photos.search
复制代码
  
  1.              &api_key={0}&text={1}&safe_search=1&sort=relevance&per_page={2}&page={3}";
复制代码
其中{0}用来输入Flickr的APIKey(只有提供这个才能访问Flickr的API)
{1}用来提供我们搜索的关键字
{2}用来提供每页返回多少个结果
{3}用来提供搜索的是第几页
采用如下方法来返回结果
     
  1.    1: public FlickrGallery(string apiKey)
复制代码
  
  1.    2: {
复制代码
  
  1.    3:     APIKey = apiKey;
复制代码
  
  1.    4: }
复制代码
  
  1.    5: 
复制代码
  
  1.    6: public void SearchPhotos(string query, uint per_page, uint page, Action<string, List<ImageInfo>> photosCallback)
复制代码
  
  1.    7: {
复制代码
  
  1.    8:     Uri searchUri = new Uri(String.Format(SearchFormattedUrl, APIKey, query, per_page.ToString(), page.ToString()));
复制代码
  
  1.    9:     WebClient imageClient = new WebClient();
复制代码
  
  1.   10:     imageClient.DownloadStringAsync(searchUri);
复制代码
  
  1.   11:     imageClient.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
复制代码
  
  1.   12:     {
复制代码
  
  1.   13:         if ((e.Cancelled == false) && (e.Error == null))
复制代码
  
  1.   14:         {
复制代码
  
  1.   15:             try
复制代码
  
  1.   16:             {
复制代码
  
  1.   17:                 string xmlStr = e.Result;
复制代码
  
  1.   18:                 if (!String.IsNullOrEmpty(xmlStr))
复制代码
  
  1.   19:                 {
复制代码
  
  1.   20:                     XDocument doc = XDocument.Parse(xmlStr);
复制代码
  
  1.   21:                     var imgs = from flickrImg in doc.Descendants("photo")
复制代码
  
  1.   22:                                select new ImageInfo()
复制代码
  
  1.   23:                                {
复制代码
  
  1.   24:                                    Title = (string)flickrImg.Attribute("title"),
复制代码
  
  1.   25:                                    ImageUrl = String.Format(ImageUrlFormat, flickrImg.Attribute("farm").Value, flickrImg.Attribute("server").Value, flickrImg.Attribute("id").Value, flickrImg.Attribute("secret").Value)
复制代码
  
  1.   26:                                };
复制代码
  
  1.   27:                     List<ImageInfo> images = imgs.ToList();
复制代码
  
  1.   28: 
复制代码
  
  1.   29:                     photosCallback(query, images);
复制代码
  
  1.   30:                     return;
复制代码
  
  1.   31:                 }
复制代码
  
  1.   32:             }
复制代码
  
  1.   33: 
复制代码
  
  1.   34:             catch
复制代码
  
  1.   35:             {
复制代码
  
  1.   36:                 photosCallback(query, null);
复制代码
  
  1.   37:             }
复制代码
  
  1.   38:         }
复制代码
  
  1.   39: 
复制代码
  
  1.   40:         else
复制代码
  
  1.   41:         {
复制代码
  
  1.   42:             photosCallback(query, null);
复制代码
  
  1.   43:         }
复制代码
  
  1.   44:     };
复制代码
  
  1.   45: }
复制代码
这里采用了LINQ语句来Parse获取得到的XML文件
接下来就是在我们的主XMAL文件中获取图片信息了
     
  1.    1: private void SearchImagesInfo()
复制代码
  
  1.    2: {
复制代码
  
  1.    3:     string query = SearchBox.Text.Trim();
复制代码
  
  1.    4:     if (query != String.Empty)
复制代码
  
  1.    5:     {
复制代码
  
  1.    6:         this.SearchingProgress.IsActive = true;
复制代码
  
  1.    7:         this.ImagePanel.Children.Clear();
复制代码
  
  1.    8:         photoGalley.SearchPhotos(query, 8, 1, OnPhotoGalleryPhotosSearched);
复制代码
  
  1.    9:     }
复制代码
  
  1.   10: }
复制代码
  
  1.   11: 
复制代码
  
  1.   12: private void OnPhotoGalleryPhotosSearched(string query, List<ImageInfo> photos)
复制代码
  
  1.   13: {
复制代码
  
  1.   14:     this.SearchingProgress.IsActive = false;
复制代码
  
  1.   15:     foreach (ImageInfo photo in photos)
复制代码
  
  1.   16:     {
复制代码
  
  1.   17:         BitmapImage bitmap = new BitmapImage(new Uri(photo.ImageUrl, UriKind.Absolute));
复制代码
  
  1.   18: 
复制代码
  
  1.   19:         int index=photos.IndexOf(photo);
复制代码
  
  1.   20: 
复制代码
  
  1.   21:         AddTheImage(bitmap, index);
复制代码
  
  1.   22:     }
复制代码
  
  1.   23: }
复制代码





其中SearchingProgress是一个效果控件
用来指示当前是否还在下载图片信息,其效果图如下
3.png

通过其属性IsActive来控制其是否可见
接下来就是将获取得到的图片添加到将用来放置图片的面板上了
     
  1.    1: private void AddTheImage(ImageSource source,int index)
复制代码
  
  1.    2: {
复制代码
  
  1.    3:     Image image = new Image()
复制代码
  
  1.    4:     {
复制代码
  
  1.    5:         Source = source
复制代码
  
  1.    6:     };
复制代码
  
  1.    7: 
复制代码
  
  1.    8:     image.Width = 200;
复制代码
  
  1.    9:     image.Height = 150;
复制代码
  
  1.   10:     image.HorizontalAlignment = HorizontalAlignment.Left;
复制代码
  
  1.   11: 
复制代码
  
  1.   12:     DropShadowEffect dsEff = new DropShadowEffect();
复制代码
  
  1.   13:     dsEff.ShadowDepth = 10;
复制代码
  
  1.   14:     dsEff.BlurRadius = 10;
复制代码
  
  1.   15:     dsEff.Color = Color.FromArgb(120, 60, 60, 60);
复制代码
  
  1.   16: 
复制代码
  
  1.   17:     image.Effect = dsEff;
复制代码
  
  1.   18: 
复制代码
  
  1.   19:     PlaneProjection projection = new PlaneProjection();
复制代码
  
  1.   20:     projection.LocalOffsetY = -index * 10;
复制代码
  
  1.   21:     projection.LocalOffsetX = index * 70;
复制代码
  
  1.   22:     projection.LocalOffsetZ = -index * 10;
复制代码
  
  1.   23:     image.Projection = projection;
复制代码
  
  1.   24:     image.MouseLeftButtonDown += new MouseButtonEventHandler(image_MouseLeftButtonDown);
复制代码
  
  1.   25:     this.ImagePanel.Children.Add(image);
复制代码
  
  1.   26: }
复制代码

在这里我对图片加了DropShadowEffect特效
大家也可以通过自定义一个投影图片来展示效果
此外这里使用了PlaneProjection来展示3D效果
我根据当前图片的编号来3D安排这些图片的位置(行19~23)
下面就是处理图片被点击的状况下图片的移动效果了
     
  1.    1: void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
复制代码
  
  1.    2: {
复制代码
  
  1.    3:     Image clickedImage = sender as Image;
复制代码
  
  1.    4: 
复制代码
  
  1.    5:     List<UIElement> elems = this.ImagePanel.Children.ToList();
复制代码
  
  1.    6:     int clickedIndex = elems.IndexOf(clickedImage);
复制代码
  
  1.    7: 
复制代码
  
  1.    8:     if (clickedIndex != 0)
复制代码
  
  1.    9:     {
复制代码
  
  1.   10:         if (isAnimateCompleted)
复制代码
  
  1.   11:             MoveImages();
复制代码
  
  1.   12:     }
复制代码
  
  1.   13: }
复制代码
  
  1.   14: 
复制代码
  
  1.   15: private void MoveImages()
复制代码
  
  1.   16: {
复制代码
  
  1.   17:     if (this.ImagePanel.Children.Count > 0)
复制代码
  
  1.   18:     {
复制代码
  
  1.   19:         isAnimateCompleted = false;
复制代码
  
  1.   20:         Image firstImage = this.ImagePanel.Children[0] as Image;
复制代码
  
  1.   21:         this.ImagePanel.Children.RemoveAt(0);
复制代码
  
  1.   22:         AddTheImage(firstImage.Source, 8);
复制代码
  
  1.   23:         Storyboard sb = new Storyboard();
复制代码
  
  1.   24:         for (int index = 0; index < this.ImagePanel.Children.Count; index++)
复制代码
  
  1.   25:         {
复制代码
  
  1.   26:             Image img = this.ImagePanel.Children[index] as Image;
复制代码
  
  1.   27: 
复制代码
  
  1.   28:             double seconds = 1.0 + index * 0.03;
复制代码
  
  1.   29: 
复制代码
  
  1.   30:             sb = AnimateStory(img, seconds, -70, 10, 10);
复制代码
  
  1.   31:             sb.Begin();
复制代码
  
  1.   32:         }
复制代码
  
  1.   33: 
复制代码
  
  1.   34:         sb.Completed += (sender, e) =>
复制代码
  
  1.   35:             {
复制代码
  
  1.   36:                 isAnimateCompleted = true;
复制代码
  
  1.   37:             };
复制代码
  
  1.   38:     }
复制代码
  
  1.   39: }
复制代码
如果点击的是第一张图片,将不会产生移动
而移动的效果我们采用自定义一个移动的Storyboard来处理
     
  1.    1: private Storyboard AnimateStory(UIElement elem, double seconds, double deltaX, double deltaY, double deltaZ)
复制代码
  
  1.    2: {
复制代码
  
  1.    3:     Storyboard sb = new Storyboard();
复制代码
  
  1.    4: 
复制代码
  
  1.    5:     DoubleAnimation dAnimX = new DoubleAnimation();
复制代码
  
  1.    6:     dAnimX.By = deltaX;
复制代码
  
  1.    7:     dAnimX.Duration = new Duration(TimeSpan.FromSeconds(seconds));
复制代码
  
  1.    8:     Storyboard.SetTargetProperty(dAnimX, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetX)"));
复制代码
  
  1.    9:     Storyboard.SetTarget(dAnimX, elem);
复制代码
  
  1.   10: 
复制代码
  
  1.   11:     DoubleAnimation dAnimY = new DoubleAnimation();
复制代码
  
  1.   12:     dAnimY.By = deltaY;
复制代码
  
  1.   13:     dAnimY.Duration = new Duration(TimeSpan.FromSeconds(1));
复制代码
  
  1.   14:     Storyboard.SetTargetProperty(dAnimY, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetY)"));
复制代码
  
  1.   15:     Storyboard.SetTarget(dAnimY, elem);
复制代码
  
  1.   16: 
复制代码
  
  1.   17:     DoubleAnimation dAnimZ = new DoubleAnimation();
复制代码
  
  1.   18:     dAnimZ.By = deltaZ;
复制代码
  
  1.   19:     dAnimZ.Duration = new Duration(TimeSpan.FromSeconds(1));
复制代码
  
  1.   20:     Storyboard.SetTargetProperty(dAnimZ, new PropertyPath("(UIElement.Projection).(PlaneProjection.LocalOffsetZ)"));
复制代码
  
  1.   21:     Storyboard.SetTarget(dAnimZ, elem);
复制代码
  
  1.   22: 
复制代码
  
  1.   23:     sb.Children.Add(dAnimX);
复制代码
  
  1.   24:     sb.Children.Add(dAnimY);
复制代码
  
  1.   25:     sb.Children.Add(dAnimZ);
复制代码
  
  1.   26: 
复制代码
  
  1.   27:     return sb;
复制代码
  
  1.   28: }
复制代码
Storyboard虽然可以使用Blend很好的获得,但是采用编程的方式会更加好控制以及好重用
这里我采用了每个图片的动画的时间不同来制造一种良好的时间差效果来增强用户体验度
     
  1. double seconds = 1.0 + index * 0.03;
复制代码
  
  1. sb = AnimateStory(img, seconds, -70, 10, 10);
复制代码
为了响应键盘,我也做了一些处理,如下     
  1. private IPhotoGallery photoGalley;
复制代码
  
  1.  
复制代码
  
  1. public MainPage(string apiKey)
复制代码
  
  1. {
复制代码
  
  1.     InitializeComponent();
复制代码
  
  1.     photoGalley = new FlickrGallery(apiKey);
复制代码
  
  1.     this.KeyDown+=(sender,e)=>
复制代码
  
  1.         {
复制代码
  
  1.             switch (e.Key)
复制代码
  
  1.             {
复制代码
  
  1.                 case Key.Enter: SearchImagesInfo(); break;
复制代码
  
  1.                 case Key.Right: if (isAnimateCompleted) { MoveImages(); } break;
复制代码
  
  1.             }
复制代码
  
  1.         };
复制代码
  
  1. }
复制代码
当按下Enter键后将开始搜索图片信息而按下右向箭头->将开始切换图片大家可能注意到了MainPage带了个参数apiKey(一般来说默认的xaml.cs文件的类初始化时不带参数)这里为了解耦合(不硬编码),采用外部输入Flickr API Key来实现于是我们通过InitParameters来从asp.net页面中传递参数过来           
  1. [/code]      
  2. 接下来就可以在App.xaml.cs文件中Parse出初始化的参数,并传递给MainPage
  3.       [code]private void Application_Startup(object sender, StartupEventArgs e)
复制代码
  
  1. {
复制代码
  
  1.     string flickrKey = "";
复制代码
  
  1.     if (e.InitParams.ContainsKey("FlickrKey"))
复制代码
  
  1.     {
复制代码
  
  1.         flickrKey = e.InitParams["FlickrKey"];
复制代码
  
  1.     }
复制代码
  
  1.     this.RootVisual = new MainPage(flickrKey);
复制代码
  
  1. }
复制代码
代码下载:


作者:ibillguo   
出处:http://ibillguo.cnblogs.com/   
本文版权由作者和博客园共同所有,转载请注明出处
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册