MyException - 我的异常网
当前位置:我的异常网» .NET相关 » WinPhone学习笔记(4)——磁贴

WinPhone学习笔记(4)——磁贴

www.MyException.Cn  网友分享于:2015-02-08  浏览:0次
WinPhone学习笔记(四)——磁贴

对每个Windows Phone的使用者来说,给他们的第一印象就是大大小小的磁贴——Metro,本篇介绍的是Windows Phone的磁贴,提到的有开始菜单的磁贴,也有在App里面的磁贴。

开始菜单的磁贴

首先介绍了一下每个磁贴的构造,每个磁贴分正反两面,正反两面都有图标,而正面有一个标题和统计数量(一般用作消息推送的时候用),在背面就有一个描述性的内容,下图就摘自MSDN上的图片,图中黑色字体其实就是每个磁贴数据类的属性,这个稍后会提到

对于一个磁贴来说,他的图片像素建议是173*173像素的,占用空间控制在80KB以内,它各个部分更详尽的数据大小如下图。

在开始菜单中的磁贴分两类,一类是App本身启动用的,通过在应用程序列表中创建的磁贴,叫应用程序磁贴;另一类是由App创建的,那个叫次要磁贴。

在控制开始菜单上的磁贴,主要有两个类,一个是StandandTileData,另一个是ShellTile。前者则是之前提过有一个类存储磁贴上的数据信息那个类,后者是负责管理开始菜单中的磁贴(包括了增删改查),但只局限于本App的磁贴。

下面的代码则磁贴创建的代码

 1 StandardTileData tileData = new StandardTileData()
 2 
 3 {
 4 
 5 Title = "Test Tile",
 6 
 7 BackContent = "The " + ShellTile.ActiveTiles.Count() + " One",
 8 
 9 BackTitle = ShellTile.ActiveTiles.Count().ToString(),
10 
11 Count = ShellTile.ActiveTiles.Count()
12 
13 };
14 
15 ShellTile.Create(new Uri(NavigationService.Source.ToString()+"?key="+Guid.NewGuid().ToString(), UriKind.Relative), tileData);

添加磁贴就是ShellTile的静态方法Create,传入的是点击磁贴后要跳转到的页面的URI还有这个磁贴的数据类,对于上面的代码,如果创建了一次磁贴之后再次执行则会抛出异常,原因在于对一个App的次要磁贴来说,它们的URI不允许重复,那遇到创建多个磁贴都是跳转到相同的页面时,可以给URI上面加上不同是QueryString来使得各个URI不一样。

ShellTile的ActiveTiles静态属性是获取这个App所有开始菜单上磁贴的枚举,是一个ShellTile的泛型集合。要获取这个App中的某一个磁贴只能遍历这个集合。有个特别之处就是不管这个App有没有放应用程序磁贴到开始菜单中,第一个元素绝对是应用程序磁贴,次要磁贴则是从第二个元素开始。

更新磁贴只是从ActiveTiles获取了相应的磁贴类之后,然后用一个StandandTileData赋上新的值,通过该磁贴的ShellTile实例的Update方法把StandandTileData传过去就可以了。

删除磁贴也是通过ActiveTiles获取了相应的磁贴类ShellTile实例,再调用它的Delete方法,但注意的一点是这里的删除只能删除次要磁贴,应用程序磁贴是不允许删除的。

应用程序内部的磁贴

类似开始菜单中的磁贴也可以添加到App内部。但它就不是ShellTile了,是HubTile,这个控件并非单纯从工具箱可以拖到页面中去,这个需要引用Toolkit,在以前WP7时使用Toolkit相对简单,但是WP8的话则需要联机获取dll了。

在vs中打开"扩展与更新"窗口,搜索"Nuget";

搜索出来了"Nuget Package Manager"便安装,安装完毕后就记得重启VS;在"扩展与更新"窗口中重启"Nuget Package Manager"。

现在就可以在引用文件夹中添加dll了。选的是"管理NuGet程序包"。

搜索"windows phone toolkit"进行安装,

最后在包管理器控制台中输入命令"Install-Package WPToolkit"就可以完成dll的添加了。包管理控制台打开方式如下图。

在需要使用该dll的xaml页面肯要添加对应的xml命名空间

Xmlns:toolkit="clr-namespace;Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" 

在xaml中添加下面语句则可以往页面成功添加一个磁贴

<toolkit:HubTile Grid.Row="1" Grid.Column="1" Background="Red" Source="Assets/Tiles/FlipCycleTileSmall.png" Title="Metro" Message="This is Metro in App"/>

一个HubTile一共有下面五种状态,这个这个磁贴用到的属性其实在上面一条语句中都可以看出来,Background是磁贴的背景色;Source是磁贴中图片,这个图片就只有一面才有,反面就没有了,Title则是那个很醒目的磁贴的标题,在磁贴的背面也有;Message是在磁贴背面

 

运行的时候会发现磁贴是贴在了页面上了,但是手点击上去就没有了开始菜单中的那种倾斜效果,这个磁贴的倾斜效果是这个Toolkit的另外一个附加属性 TiltEffect.IsEnable。它是一个布尔类型,True表示使用倾斜效果。还需要在隐藏文件的构造函数中加入这个控件的类型

<toolkit:HubTile toolkit:TiltEffect.IsTiltEnabled="True" Grid.Row="1" Grid.Column="1" Background="Red" Source="Assets/Tiles/FlipCycleTileSmall.png" Title="Metro" Message="This is Metro in App"/>

 

public TileTestPage()

{

InitializeComponent();

ControlTiltEffect.TiltEffect.TiltableItems.Add(typeof(HubTile));

}

 

但是用Toolkit的效果不是很明显,而且有限制,有一些控件虽然用上了但也没有倾斜的效果。在网上查看资料时发现有个老外也写了一个倾斜效果,效果比微软提供的要明显,而且还可以调节倾斜的角度。两个类的代码如下

  1 using System;
  2 using System.Windows;
  3 using System.Windows.Controls;
  4 using System.Windows.Input;
  5 using System.Windows.Media;
  6 using System.Windows.Media.Animation;
  7 using System.Collections.Generic;
  8 using System.Windows.Controls.Primitives;
  9 
 10 
 11 #if WINDOWS_PHONE
 12 using Microsoft.Phone.Controls;
 13 #endif
 14 
 15 namespace ControlTiltEffect
 16 {
 17     /// <summary>
 18     /// This code provides attached properties for adding a 'tilt' effect to all controls within a container.
 19     /// </summary>
 20     public class TiltEffect : DependencyObject
 21     {
 22 
 23         #region Constructor and Static Constructor
 24         /// <summary>
 25         /// This is not a constructable class, but it cannot be static because it derives from DependencyObject.
 26         /// </summary>
 27         private TiltEffect()
 28         {
 29         }
 30 
 31         /// <summary>
 32         /// Initialize the static properties
 33         /// </summary>
 34         static TiltEffect()
 35         {
 36             // The tiltable items list.
 37             TiltableItems = new List<Type>() { typeof(ButtonBase), typeof(ListBoxItem) };
 38             UseLogarithmicEase = false;
 39         }
 40 
 41         #endregion
 42 
 43 
 44         #region Fields and simple properties
 45 
 46         // These constants are the same as the built-in effects
 47         /// <summary>
 48         /// Maximum amount of tilt, in radians
 49         /// </summary>
 50         const double MaxAngle = 0.3;
 51 
 52         /// <summary>
 53         /// Maximum amount of depression, in pixels
 54         /// </summary>
 55         const double MaxDepression = 25;
 56 
 57         /// <summary>
 58         /// Delay between releasing an element and the tilt release animation playing
 59         /// </summary>
 60         static readonly TimeSpan TiltReturnAnimationDelay = TimeSpan.FromMilliseconds(200);
 61 
 62         /// <summary>
 63         /// Duration of tilt release animation
 64         /// </summary>
 65         static readonly TimeSpan TiltReturnAnimationDuration = TimeSpan.FromMilliseconds(100);
 66 
 67         /// <summary>
 68         /// The control that is currently being tilted
 69         /// </summary>
 70         static FrameworkElement currentTiltElement;
 71 
 72         /// <summary>
 73         /// The single instance of a storyboard used for all tilts
 74         /// </summary>
 75         static Storyboard tiltReturnStoryboard;
 76 
 77         /// <summary>
 78         /// The single instance of an X rotation used for all tilts
 79         /// </summary>
 80         static DoubleAnimation tiltReturnXAnimation;
 81 
 82         /// <summary>
 83         /// The single instance of a Y rotation used for all tilts
 84         /// </summary>
 85         static DoubleAnimation tiltReturnYAnimation;
 86 
 87         /// <summary>
 88         /// The single instance of a Z depression used for all tilts
 89         /// </summary>
 90         static DoubleAnimation tiltReturnZAnimation;
 91 
 92         /// <summary>
 93         /// The center of the tilt element
 94         /// </summary>
 95         static Point currentTiltElementCenter;
 96 
 97         /// <summary>
 98         /// Whether the animation just completed was for a 'pause' or not
 99         /// </summary>
100         static bool wasPauseAnimation = false;
101 
102         /// <summary>
103         /// Whether to use a slightly more accurate (but slightly slower) tilt animation easing function
104         /// </summary>
105         public static bool UseLogarithmicEase { get; set; }
106 
107         /// <summary>
108         /// Default list of items that are tiltable
109         /// </summary>
110         public static List<Type> TiltableItems { get; private set; }
111 
112         #endregion
113 
114 
115         #region Dependency properties
116 
117         /// <summary>
118         /// Whether the tilt effect is enabled on a container (and all its children)
119         /// </summary>
120         public static readonly DependencyProperty IsTiltEnabledProperty = DependencyProperty.RegisterAttached(
121           "IsTiltEnabled",
122           typeof(bool),
123           typeof(TiltEffect),
124           new PropertyMetadata(OnIsTiltEnabledChanged)
125           );
126 
127         /// <summary>
128         /// Gets the IsTiltEnabled dependency property from an object
129         /// </summary>
130         /// <param name="source">The object to get the property from</param>
131         /// <returns>The property's value</returns>
132         public static bool GetIsTiltEnabled(DependencyObject source) { return (bool)source.GetValue(IsTiltEnabledProperty); }
133 
134         /// <summary>
135         /// Sets the IsTiltEnabled dependency property on an object
136         /// </summary>
137         /// <param name="source">The object to set the property on</param>
138         /// <param name="value">The value to set</param>
139         public static void SetIsTiltEnabled(DependencyObject source, bool value) { source.SetValue(IsTiltEnabledProperty, value); }
140 
141         /// <summary>
142         /// Suppresses the tilt effect on a single control that would otherwise be tilted
143         /// </summary>
144         public static readonly DependencyProperty SuppressTiltProperty = DependencyProperty.RegisterAttached(
145           "SuppressTilt",
146           typeof(bool),
147           typeof(TiltEffect),
148           null
149           );
150 
151         /// <summary>
152         /// Gets the SuppressTilt dependency property from an object
153         /// </summary>
154         /// <param name="source">The object to get the property from</param>
155         /// <returns>The property's value</returns>
156         public static bool GetSuppressTilt(DependencyObject source) { return (bool)source.GetValue(SuppressTiltProperty); }
157 
158         /// <summary>
159         /// Sets the SuppressTilt dependency property from an object
160         /// </summary>
161         /// <param name="source">The object to get the property from</param>
162         /// <returns>The property's value</returns>
163         public static void SetSuppressTilt(DependencyObject source, bool value) { source.SetValue(SuppressTiltProperty, value); }
164 
165 
166         /// <summary>
167         /// Property change handler for the IsTiltEnabled dependency property
168         /// </summary>
169         /// <param name="target">The element that the property is atteched to</param>
170         /// <param name="args">Event args</param>
171         /// <remarks>
172         /// Adds or removes event handlers from the element that has been (un)registered for tilting
173         /// </remarks>
174         static void OnIsTiltEnabledChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
175         {
176             if (target is FrameworkElement)
177             {
178                 // Add / remove the event handler if necessary
179                 if ((bool)args.NewValue == true)
180                 {
181                     (target as FrameworkElement).ManipulationStarted += TiltEffect_ManipulationStarted;
182                 }
183                 else
184                 {
185                     (target as FrameworkElement).ManipulationStarted -= TiltEffect_ManipulationStarted;
186                 }
187             }
188         }
189 
190         #endregion
191 
192 
193         #region Top-level manipulation event handlers
194 
195         /// <summary>
196         /// Event handler for ManipulationStarted
197         /// </summary>
198         /// <param name="sender">sender of the event - this will be the tilt container (eg, entire page)</param>
199         /// <param name="e">event args</param>
200         static void TiltEffect_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
201         {
202 
203             TryStartTiltEffect(sender as FrameworkElement, e);
204         }
205 
206         /// <summary>
207         /// Event handler for ManipulationDelta
208         /// </summary>
209         /// <param name="sender">sender of the event - this will be the tilting object (eg a button)</param>
210         /// <param name="e">event args</param>
211         static void TiltEffect_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
212         {
213 
214             ContinueTiltEffect(sender as FrameworkElement, e);
215         }
216 
217         /// <summary>
218         /// Event handler for ManipulationCompleted
219         /// </summary>
220         /// <param name="sender">sender of the event - this will be the tilting object (eg a button)</param>
221         /// <param name="e">event args</param>
222         static void TiltEffect_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
223         {
224 
225             EndTiltEffect(currentTiltElement);
226         }
227 
228         #endregion
229 
230 
231         #region Core tilt logic
232 
233         /// <summary>
234         /// Checks if the manipulation should cause a tilt, and if so starts the tilt effect
235         /// </summary>
236         /// <param name="source">The source of the manipulation (the tilt container, eg entire page)</param>
237         /// <param name="e">The args from the ManipulationStarted event</param>
238         static void TryStartTiltEffect(FrameworkElement source, ManipulationStartedEventArgs e)
239         {
240             foreach (FrameworkElement ancestor in (e.OriginalSource as FrameworkElement).GetVisualAncestors())
241             {
242                 foreach (Type t in TiltableItems)
243                 {
244                     if (t.IsAssignableFrom(ancestor.GetType()))
245                     {
246                         if ((bool)ancestor.GetValue(SuppressTiltProperty) != true)
247                         {
248                             // Use first child of the control, so that you can add transforms and not
249                             // impact any transforms on the control itself
250                             FrameworkElement element = VisualTreeHelper.GetChild(ancestor, 0) as FrameworkElement;
251                             FrameworkElement container = e.ManipulationContainer as FrameworkElement;
252 
253                             if (element == null || container == null)
254                                 return;
255 
256                             // Touch point relative to the element being tilted
257                             Point tiltTouchPoint = container.TransformToVisual(element).Transform(e.ManipulationOrigin);
258 
259                             // Center of the element being tilted
260                             Point elementCenter = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
261 
262                             // Camera adjustment
263                             Point centerToCenterDelta = GetCenterToCenterDelta(element, source);
264 
265                             BeginTiltEffect(element, tiltTouchPoint, elementCenter, centerToCenterDelta);
266                             return;
267                         }
268                     }
269                 }
270             }
271         }
272 
273         /// <summary>
274         /// Computes the delta between the centre of an element and its container
275         /// </summary>
276         /// <param name="element">The element to compare</param>
277         /// <param name="container">The element to compare against</param>
278         /// <returns>A point that represents the delta between the two centers</returns>
279         static Point GetCenterToCenterDelta(FrameworkElement element, FrameworkElement container)
280         {
281             Point elementCenter = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
282             Point containerCenter;
283 
284 #if WINDOWS_PHONE
285 
286             // Need to special-case the frame to handle different orientations
287             if (container is PhoneApplicationFrame)
288             {
289                 PhoneApplicationFrame frame = container as PhoneApplicationFrame;
290 
291                 // Switch width and height in landscape mode
292                 if ((frame.Orientation & PageOrientation.Landscape) == PageOrientation.Landscape)
293                 {
294 
295                     containerCenter = new Point(container.ActualHeight / 2, container.ActualWidth / 2);
296                 }
297                 else
298                     containerCenter = new Point(container.ActualWidth / 2, container.ActualHeight / 2);
299             }
300             else
301                 containerCenter = new Point(container.ActualWidth / 2, container.ActualHeight / 2);
302 #else
303 
304             containerCenter = new Point(container.ActualWidth / 2, container.ActualHeight / 2);
305 
306 #endif
307 
308             Point transformedElementCenter = element.TransformToVisual(container).Transform(elementCenter);
309             Point result = new Point(containerCenter.X - transformedElementCenter.X, containerCenter.Y - transformedElementCenter.Y);
310 
311             return result;
312         }
313 
314         /// <summary>
315         /// Begins the tilt effect by preparing the control and doing the initial animation
316         /// </summary>
317         /// <param name="element">The element to tilt </param>
318         /// <param name="touchPoint">The touch point, in element coordinates</param>
319         /// <param name="centerPoint">The center point of the element in element coordinates</param>
320         /// <param name="centerDelta">The delta between the <paramref name="element"/>'s center and 
321         /// the container's center</param>
322         static void BeginTiltEffect(FrameworkElement element, Point touchPoint, Point centerPoint, Point centerDelta)
323         {
324 
325 
326             if (tiltReturnStoryboard != null)
327                 StopTiltReturnStoryboardAndCleanup();
328 
329             if (PrepareControlForTilt(element, centerDelta) == false)
330                 return;
331 
332             currentTiltElement = element;
333             currentTiltElementCenter = centerPoint;
334             PrepareTiltReturnStoryboard(element);
335 
336             ApplyTiltEffect(currentTiltElement, touchPoint, currentTiltElementCenter);
337         }
338 
339         /// <summary>
340         /// Prepares a control to be tilted by setting up a plane projection and some event handlers
341         /// </summary>
342         /// <param name="element">The control that is to be tilted</param>
343         /// <param name="centerDelta">Delta between the element's center and the tilt container's</param>
344         /// <returns>true if successful; false otherwise</returns>
345         /// <remarks>
346         /// This method is conservative; it will fail any attempt to tilt a control that already
347         /// has a projection on it
348         /// </remarks>
349         static bool PrepareControlForTilt(FrameworkElement element, Point centerDelta)
350         {
351             // Prevents interference with any existing transforms
352             if (element.Projection != null || (element.RenderTransform != null && element.RenderTransform.GetType() != typeof(MatrixTransform)))
353                 return false;
354 
355             TranslateTransform transform = new TranslateTransform();
356             transform.X = centerDelta.X;
357             transform.Y = centerDelta.Y;
358             element.RenderTransform = transform;
359 
360             PlaneProjection projection = new PlaneProjection();
361             projection.GlobalOffsetX = -1 * centerDelta.X;
362             projection.GlobalOffsetY = -1 * centerDelta.Y;
363             element.Projection = projection;
364 
365             element.ManipulationDelta += TiltEffect_ManipulationDelta;
366             element.ManipulationCompleted += TiltEffect_ManipulationCompleted;
367 
368             return true;
369         }
370 
371         /// <summary>
372         /// Removes modifications made by PrepareControlForTilt
373         /// </summary>
374         /// <param name="element">THe control to be un-prepared</param>
375         /// <remarks>
376         /// This method is basic; it does not do anything to detect if the control being un-prepared
377         /// was previously prepared
378         /// </remarks>
379         static void RevertPrepareControlForTilt(FrameworkElement element)
380         {
381             element.ManipulationDelta -= TiltEffect_ManipulationDelta;
382             element.ManipulationCompleted -= TiltEffect_ManipulationCompleted;
383             element.Projection = null;
384             element.RenderTransform = null;
385         }
386 
387         /// <summary>
388         /// Creates the tilt return storyboard (if not already created) and targets it to the projection
389         /// </summary>
390         /// <param name="projection">the projection that should be the target of the animation</param>
391         static void PrepareTiltReturnStoryboard(FrameworkElement element)
392         {
393 
394             if (tiltReturnStoryboard == null)
395             {
396                 tiltReturnStoryboard = new Storyboard();
397                 tiltReturnStoryboard.Completed += TiltReturnStoryboard_Completed;
398 
399                 tiltReturnXAnimation = new DoubleAnimation();
400                 Storyboard.SetTargetProperty(tiltReturnXAnimation, new PropertyPath(PlaneProjection.RotationXProperty));
401                 tiltReturnXAnimation.BeginTime = TiltReturnAnimationDelay;
402                 tiltReturnXAnimation.To = 0;
403                 tiltReturnXAnimation.Duration = TiltReturnAnimationDuration;
404 
405                 tiltReturnYAnimation = new DoubleAnimation();
406                 Storyboard.SetTargetProperty(tiltReturnYAnimation, new PropertyPath(PlaneProjection.RotationYProperty));
407                 tiltReturnYAnimation.BeginTime = TiltReturnAnimationDelay;
408                 tiltReturnYAnimation.To = 0;
409                 tiltReturnYAnimation.Duration = TiltReturnAnimationDuration;
410 
411                 tiltReturnZAnimation = new DoubleAnimation();
412                 Storyboard.SetTargetProperty(tiltReturnZAnimation, new PropertyPath(PlaneProjection.GlobalOffsetZProperty));
413                 tiltReturnZAnimation.BeginTime = TiltReturnAnimationDelay;
414                 tiltReturnZAnimation.To = 0;
415                 tiltReturnZAnimation.Duration = TiltReturnAnimationDuration;
416 
417                 if (UseLogarithmicEase)
418                 {
419                     tiltReturnXAnimation.EasingFunction = new LogarithmicEase();
420                     tiltReturnYAnimation.EasingFunction = new LogarithmicEase();
421                     tiltReturnZAnimation.EasingFunction = new LogarithmicEase();
422                 }
423 
424                 tiltReturnStoryboard.Children.Add(tiltReturnXAnimation);
425                 tiltReturnStoryboard.Children.Add(tiltReturnYAnimation);
426                 tiltReturnStoryboard.Children.Add(tiltReturnZAnimation);
427             }
428 
429             Storyboard.SetTarget(tiltReturnXAnimation, element.Projection);
430             Storyboard.SetTarget(tiltReturnYAnimation, element.Projection);
431             Storyboard.SetTarget(tiltReturnZAnimation, element.Projection);
432         }
433 
434 
435         /// <summary>
436         /// Continues a tilt effect that is currently applied to an element, presumably because
437         /// the user moved their finger
438         /// </summary>
439         /// <param name="element">The element being tilted</param>
440         /// <param name="e">The manipulation event args</param>
441         static void ContinueTiltEffect(FrameworkElement element, ManipulationDeltaEventArgs e)
442         {
443             FrameworkElement container = e.ManipulationContainer as FrameworkElement;
444             if (container == null || element == null)
445                 return;
446 
447             Point tiltTouchPoint = container.TransformToVisual(element).Transform(e.ManipulationOrigin);
448 
449             // If touch moved outside bounds of element, then pause the tilt (but don't cancel it)
450             if (new Rect(0, 0, currentTiltElement.ActualWidth, currentTiltElement.ActualHeight).Contains(tiltTouchPoint) != true)
451             {
452 
453                 PauseTiltEffect();
454                 return;
455             }
456 
457             // Apply the updated tilt effect
458             ApplyTiltEffect(currentTiltElement, e.ManipulationOrigin, currentTiltElementCenter);
459         }
460 
461         /// <summary>
462         /// Ends the tilt effect by playing the animation  
463         /// </summary>
464         /// <param name="element">The element being tilted</param>
465         static void EndTiltEffect(FrameworkElement element)
466         {
467             if (element != null)
468             {
469                 element.ManipulationCompleted -= TiltEffect_ManipulationCompleted;
470                 element.ManipulationDelta -= TiltEffect_ManipulationDelta;
471             }
472 
473             if (tiltReturnStoryboard != null)
474             {
475                 wasPauseAnimation = false;
476                 if (tiltReturnStoryboard.GetCurrentState() != ClockState.Active)
477                     tiltReturnStoryboard.Begin();
478             }
479             else
480                 StopTiltReturnStoryboardAndCleanup();
481         }
482 
483         /// <summary>
484         /// Handler for the storyboard complete event
485         /// </summary>
486         /// <param name="sender">sender of the event</param>
487         /// <param name="e">event args</param>
488         static void TiltReturnStoryboard_Completed(object sender, EventArgs e)
489         {
490             if (wasPauseAnimation)
491                 ResetTiltEffect(currentTiltElement);
492             else
493                 StopTiltReturnStoryboardAndCleanup();
494         }
495 
496         /// <summary>
497         /// Resets the tilt effect on the control, making it appear 'normal' again 
498         /// </summary>
499         /// <param name="element">The element to reset the tilt on</param>
500         /// <remarks>
501         /// This method doesn't turn off the tilt effect or cancel any current
502         /// manipulation; it just temporarily cancels the effect
503         /// </remarks>
504         static void ResetTiltEffect(FrameworkElement element)
505         {
506             PlaneProjection projection = element.Projection as PlaneProjection;
507             projection.RotationY = 0;
508             projection.RotationX = 0;
509             projection.GlobalOffsetZ = 0;
510         }
511 
512         /// <summary>
513         /// Stops the tilt effect and release resources applied to the currently-tilted control
514         /// </summary>
515         static void StopTiltReturnStoryboardAndCleanup()
516         {
517             if (tiltReturnStoryboard != null)
518                 tiltReturnStoryboard.Stop();
519 
520             RevertPrepareControlForTilt(currentTiltElement);
521         }
522 
523         /// <summary>
524         /// Pauses the tilt effect so that the control returns to the 'at rest' position, but doesn't
525         /// stop the tilt effect (handlers are still attached, etc.)
526         /// </summary>
527         static void PauseTiltEffect()
528         {
529             if ((tiltReturnStoryboard != null) && !wasPauseAnimation)
530             {
531                 tiltReturnStoryboard.Stop();
532                 wasPauseAnimation = true;
533                 tiltReturnStoryboard.Begin();
534             }
535         }
536 
537         /// <summary>
538         /// Resets the storyboard to not running
539         /// </summary>
540         private static void ResetTiltReturnStoryboard()
541         {
542             tiltReturnStoryboard.Stop();
543             wasPauseAnimation = false;
544         }
545 
546         /// <summary>
547         /// Applies the tilt effect to the control
548         /// </summary>
549         /// <param name="element">the control to tilt</param>
550         /// <param name="touchPoint">The touch point, in the container's coordinates</param>
551         /// <param name="centerPoint">The center point of the container</param>
552         static void ApplyTiltEffect(FrameworkElement element, Point touchPoint, Point centerPoint)
553         {
554             // Stop any active animation
555             ResetTiltReturnStoryboard();
556 
557             // Get relative point of the touch in percentage of container size
558             Point normalizedPoint = new Point(
559                 Math.Min(Math.Max(touchPoint.X / (centerPoint.X * 2), 0), 1),
560                 Math.Min(Math.Max(touchPoint.Y / (centerPoint.Y * 2), 0), 1));
561 
562             // Shell values
563             double xMagnitude = Math.Abs(normalizedPoint.X - 0.5);
564             double yMagnitude = Math.Abs(normalizedPoint.Y - 0.5);
565             double xDirection = -Math.Sign(normalizedPoint.X - 0.5);
566             double yDirection = Math.Sign(normalizedPoint.Y - 0.5);
567             double angleMagnitude = xMagnitude + yMagnitude;
568             double xAngleContribution = xMagnitude + yMagnitude > 0 ? xMagnitude / (xMagnitude + yMagnitude) : 0;
569 
570             double angle = angleMagnitude * MaxAngle * 180 / Math.PI;
571             double depression = (1 - angleMagnitude) * MaxDepression;
572 
573             // RotationX and RotationY are the angles of rotations about the x- or y-*axis*;
574             // to achieve a rotation in the x- or y-*direction*, we need to swap the two.
575             // That is, a rotation to the left about the y-axis is a rotation to the left in the x-direction,
576             // and a rotation up about the x-axis is a rotation up in the y-direction.
577             PlaneProjection projection = element.Projection as PlaneProjection;
578             projection.RotationY = angle * xAngleContribution * xDirection;
579             projection.RotationX = angle * (1 - xAngleContribution) * yDirection;
580             projection.GlobalOffsetZ = -depression;
581         }
582 
583         #endregion
584 
585 
586         #region Custom easing function
587 
588         /// <summary>
589         /// Provides an easing function for the tilt return
590         /// </summary>
591         private class LogarithmicEase : EasingFunctionBase
592         {
593             /// <summary>
594             /// Computes the easing function
595             /// </summary>
596             /// <param name="normalizedTime">The time</param>
597             /// <returns>The eased value</returns>
598             protected override double EaseInCore(double normalizedTime)
599             {
600                 return Math.Log(normalizedTime + 1) / 0.693147181; // ln(t + 1) / ln(2)
601             }
602         }
603 
604         #endregion
605     }
606 
607     /// <summary>
608     /// Couple of simple helpers for walking the visual tree
609     /// </summary>
610     static class TreeHelpers
611     {
612         /// <summary>
613         /// Gets the ancestors of the element, up to the root
614         /// </summary>
615         /// <param name="node">The element to start from</param>
616         /// <returns>An enumerator of the ancestors</returns>
617         public static IEnumerable<FrameworkElement> GetVisualAncestors(this FrameworkElement node)
618         {
619             FrameworkElement parent = node.GetVisualParent();
620             while (parent != null)
621             {
622                 yield return parent;
623                 parent = parent.GetVisualParent();
624             }
625         }
626 
627         /// <summary>
628         /// Gets the visual parent of the element
629         /// </summary>
630         /// <param name="node">The element to check</param>
631         /// <returns>The visual parent</returns>
632         public static FrameworkElement GetVisualParent(this FrameworkElement node)
633         {
634             return VisualTreeHelper.GetParent(node) as FrameworkElement;
635         }
636     }
637 }
TiltEffect.cs
  1     public static class MetroInMotion
  2     {
  3         #region AnimationLevel
  4 
  5         public static int GetAnimationLevel(DependencyObject obj)
  6         {
  7             return (int)obj.GetValue(AnimationLevelProperty);
  8         }
  9 
 10         public static void SetAnimationLevel(DependencyObject obj, int value)
 11         {
 12             obj.SetValue(AnimationLevelProperty, value);
 13         }
 14 
 15 
 16         public static readonly DependencyProperty AnimationLevelProperty =
 17             DependencyProperty.RegisterAttached("AnimationLevel", typeof(int),
 18             typeof(MetroInMotion), new PropertyMetadata(-1));
 19 
 20         #endregion
 21 
 22         #region Tilt
 23 
 24         public static double GetTilt(DependencyObject obj)
 25         {
 26             return (double)obj.GetValue(TiltProperty);
 27         }
 28 
 29         public static void SetTilt(DependencyObject obj, double value)
 30         {
 31             obj.SetValue(TiltProperty, value);
 32         }
 33 
 34 
 35         public static readonly DependencyProperty TiltProperty =
 36             DependencyProperty.RegisterAttached("Tilt", typeof(double),
 37             typeof(MetroInMotion), new PropertyMetadata(2.0, OnTiltChanged));
 38 
 39         /// <summary>
 40         /// The extent of the tilt action, the larger the number, the bigger the tilt
 41         /// </summary>
 42         private static double TiltAngleFactor = 4;
 43 
 44         /// <summary>
 45         /// The extent of the scaling action, the smaller the number, the greater the scaling.
 46         /// </summary>
 47         private static double ScaleFactor = 100;
 48 
 49         private static void OnTiltChanged(DependencyObject d,
 50           DependencyPropertyChangedEventArgs args)
 51         {
 52             FrameworkElement targetElement = d as FrameworkElement;
 53 
 54             double tiltFactor = GetTilt(d);
 55 
 56             // create the required transformations
 57             var projection = new PlaneProjection();
 58             var scale = new ScaleTransform();
 59             var translate = new TranslateTransform();
 60 
 61             var transGroup = new TransformGroup();
 62             transGroup.Children.Add(scale);
 63             transGroup.Children.Add(translate);
 64 
 65             // associate with the target element
 66             targetElement.Projection = projection;
 67             targetElement.RenderTransform = transGroup;
 68             targetElement.RenderTransformOrigin = new Point(0.5, 0.5);
 69 
 70             targetElement.MouseLeftButtonDown += (s, e) =>
 71             {
 72                 var clickPosition = e.GetPosition(targetElement);
 73 
 74                 // find the maximum of width / height
 75                 double maxDimension = Math.Max(targetElement.ActualWidth, targetElement.ActualHeight);
 76 
 77                 // compute the normalised horizontal distance from the centre
 78                 double distanceFromCenterX = targetElement.ActualWidth / 2 - clickPosition.X;
 79                 double normalisedDistanceX = 2 * distanceFromCenterX / maxDimension;
 80 
 81                 // rotate around the Y axis 
 82                 projection.RotationY = normalisedDistanceX * TiltAngleFactor * tiltFactor;
 83 
 84                 // compute the normalised vertical distance from the centre
 85                 double distanceFromCenterY = targetElement.ActualHeight / 2 - clickPosition.Y;
 86                 double normalisedDistanceY = 2 * distanceFromCenterY / maxDimension;
 87 
 88                 // rotate around the X axis, 
 89                 projection.RotationX = -normalisedDistanceY * TiltAngleFactor * tiltFactor;
 90 
 91                 // find the distance to centre
 92                 double distanceToCentre = Math.Sqrt(normalisedDistanceX * normalisedDistanceX
 93                   + normalisedDistanceY * normalisedDistanceY);
 94 
 95                 // scale accordingly
 96                 double scaleVal = tiltFactor * (1 - distanceToCentre) / ScaleFactor;
 97                 scale.ScaleX = 1 - scaleVal;
 98                 scale.ScaleY = 1 - scaleVal;
 99 
100                 // offset the plane transform
101                 var rootElement = Application.Current.RootVisual as FrameworkElement;
102                 var relativeToCentre = (targetElement.GetRelativePosition(rootElement).Y - rootElement.ActualHeight / 2) / 2;
103                 translate.Y = -relativeToCentre;
104                 projection.LocalOffsetY = +relativeToCentre;
105 
106             };
107 
108             targetElement.ManipulationCompleted += (s, e) =>
109             {
110                 var sb = new Storyboard();
111                 sb.Children.Add(CreateAnimation(null, 0, 0.1, "RotationY", projection));
112                 sb.Children.Add(CreateAnimation(null, 0, 0.1, "RotationX", projection));
113                 sb.Children.Add(CreateAnimation(null, 1, 0.1, "ScaleX", scale));
114                 sb.Children.Add(CreateAnimation(null, 1, 0.1, "ScaleY", scale));
115                 sb.Begin();
116 
117                 translate.Y = 0;
118                 projection.LocalOffsetY = 0;
119             };
120 
121         }
122 
123 
124         #endregion
125 
126         #region IsPivotAnimated
127 
128         public static bool GetIsPivotAnimated(DependencyObject obj)
129         {
130             return (bool)obj.GetValue(IsPivotAnimatedProperty);
131         }
132 
133         public static void SetIsPivotAnimated(DependencyObject obj, bool value)
134         {
135             obj.SetValue(IsPivotAnimatedProperty, value);
136         }
137 
138         public static readonly DependencyProperty IsPivotAnimatedProperty =
139             DependencyProperty.RegisterAttached("IsPivotAnimated", typeof(bool),
140             typeof(MetroInMotion), new PropertyMetadata(false, OnIsPivotAnimatedChanged));
141 
142         private static void OnIsPivotAnimatedChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
143         {
144             ItemsControl list = d as ItemsControl;
145 
146             list.Loaded += (s2, e2) =>
147             {
148                 // locate the pivot control that this list is within
149                 Pivot pivot = list.Ancestors<Pivot>().Single() as Pivot;
150 
151                 // and its index within the pivot
152                 int pivotIndex = pivot.Items.IndexOf(list.Ancestors<PivotItem>().Single());
153 
154                 bool selectionChanged = false;
155 
156                 pivot.SelectionChanged += (s3, e3) =>
157                 {
158                     selectionChanged = true;
159                 };
160 
161                 // handle manipulation events which occur when the user
162                 // moves between pivot items
163                 pivot.ManipulationCompleted += (s, e) =>
164                 {
165                     if (!selectionChanged)
166                         return;
167 
168                     selectionChanged = false;
169 
170                     if (pivotIndex != pivot.SelectedIndex)
171                         return;
172 
173                     // determine which direction this tab will be scrolling in from
174                     bool fromRight = e.TotalManipulation.Translation.X <= 0;
175 
176 
177                     // iterate over each of the items in view
178                     var items = list.GetItemsInView().ToList();
179                     for (int index = 0; index < items.Count; index++)
180                     {
181                         var lbi = items[index];
182 
183                         list.Dispatcher.BeginInvoke(() =>
184                         {
185                             var animationTargets = lbi.Descendants()
186                                                    .Where(p => MetroInMotion.GetAnimationLevel(p) > -1);
187                             foreach (FrameworkElement target in animationTargets)
188                             {
189                                 // trigger the required animation
190                                 GetSlideAnimation(target, fromRight).Begin();
191                             }
192                         });
193                     };
194 
195                 };
196             };
197         }
198 
199 
200         #endregion
201 
202         /// <summary>
203         /// Animates each element in order, creating a 'peel' effect. The supplied action
204         /// is invoked when the animation ends.
205         /// </summary>
206         public static void Peel(this IEnumerable<FrameworkElement> elements, Action endAction)
207         {
208             var elementList = elements.ToList();
209             var lastElement = elementList.Last();
210 
211             // iterate over all the elements, animating each of them
212             double delay = 0;
213             foreach (FrameworkElement element in elementList)
214             {
215                 var sb = GetPeelAnimation(element, delay);
216 
217                 // add a Completed event handler to the last element
218                 if (element.Equals(lastElement))
219                 {
220                     sb.Completed += (s, e) =>
221                     {
222                         endAction();
223                     };
224                 }
225 
226                 sb.Begin();
227                 delay += 50;
228             }
229         }
230 
231 
232         /// <summary>
233         /// Enumerates all the items that are currently visible in am ItemsControl. This implementation assumes
234         /// that a VirtualizingStackPanel is being used as the ItemsPanel.
235         /// </summary>
236         public static IEnumerable<FrameworkElement> GetItemsInView(this ItemsControl itemsControl)
237         {
238             // locate the stack panel that hosts the items
239             VirtualizingStackPanel vsp = itemsControl.Descendants<VirtualizingStackPanel>().First() as VirtualizingStackPanel;
240 
241             // iterate over each of the items in view
242             int firstVisibleItem = (int)vsp.VerticalOffset;
243             int visibleItemCount = (int)vsp.ViewportHeight;
244             for (int index = firstVisibleItem; index <= firstVisibleItem + visibleItemCount + 1; index++)
245             {
246                 var item = itemsControl.ItemContainerGenerator.ContainerFromIndex(index) as FrameworkElement;
247                 if (item == null)
248                     continue;
249 
250                 yield return item;
251             }
252         }
253 
254         /// <summary>
255         /// Creates a PlaneProjection and associates it with the given element, returning
256         /// a Storyboard which will animate the PlaneProjection to 'peel' the item
257         /// from the screen.
258         /// </summary>
259         private static Storyboard GetPeelAnimation(FrameworkElement element, double delay)
260         {
261             Storyboard sb;
262 
263             var projection = new PlaneProjection()
264             {
265                 CenterOfRotationX = -0.1
266             };
267             element.Projection = projection;
268 
269             // compute the angle of rotation required to make this element appear
270             // at a 90 degree angle at the edge of the screen.
271             var width = element.ActualWidth;
272             var targetAngle = Math.Atan(1000 / (width / 2));
273             targetAngle = targetAngle * 180 / Math.PI;
274 
275             // animate the projection
276             sb = new Storyboard();
277             sb.BeginTime = TimeSpan.FromMilliseconds(delay);
278             sb.Children.Add(CreateAnimation(0, -(180 - targetAngle), 0.3, "RotationY", projection));
279             sb.Children.Add(CreateAnimation(0, 23, 0.3, "RotationZ", projection));
280             sb.Children.Add(CreateAnimation(0, -23, 0.3, "GlobalOffsetZ", projection));
281             return sb;
282         }
283 
284         private static DoubleAnimation CreateAnimation(double? from, double? to, double duration,
285           string targetProperty, DependencyObject target)
286         {
287             var db = new DoubleAnimation();
288             db.To = to;
289             db.From = from;
290             db.EasingFunction = new SineEase();
291             db.Duration = TimeSpan.FromSeconds(duration);
292             Storyboard.SetTarget(db, target);
293             Storyboard.SetTargetProperty(db, new PropertyPath(targetProperty));
294             return db;
295         }
296 
297         /// <summary>
298         /// Creates a TranslateTransform and associates it with the given element, returning
299         /// a Storyboard which will animate the TranslateTransform with a SineEase function
300         /// </summary>
301         private static Storyboard GetSlideAnimation(FrameworkElement element, bool fromRight)
302         {
303             double from = fromRight ? 80 : -80;
304 
305             Storyboard sb;
306             double delay = (MetroInMotion.GetAnimationLevel(element)) * 0.1 + 0.1;
307 
308             TranslateTransform trans = new TranslateTransform() { X = from };
309             element.RenderTransform = trans;
310 
311             sb = new Storyboard();
312             sb.BeginTime = TimeSpan.FromSeconds(delay);
313             sb.Children.Add(CreateAnimation(from, 0, 0.8, "X", trans));
314             return sb;
315         }
316 
317     }
318 
319     public static class ExtensionMethods
320     {
321         public static Point GetRelativePosition(this UIElement element, UIElement other)
322         {
323             return element.TransformToVisual(other)
324               .Transform(new Point(0, 0));
325         }
326     }
327 
328     public class ItemFlyInAndOutAnimations
329     {
330         private Popup _popup;
331 
332         private Canvas _popupCanvas;
333 
334         private FrameworkElement _targetElement;
335 
336         private Point _targetElementPosition;
337 
338         private Image _targetElementClone;
339 
340         private Rectangle _backgroundMask;
341 
342         private static TimeSpan _flyInSpeed = TimeSpan.FromMilliseconds(200);
343 
344         private static TimeSpan _flyOutSpeed = TimeSpan.FromMilliseconds(300);
345 
346         public ItemFlyInAndOutAnimations()
347         {
348             // construct a popup, with a Canvas as its child
349             _popup = new Popup();
350             _popupCanvas = new Canvas();
351             _popup.Child = _popupCanvas;
352         }
353 
354         public static void TitleFlyIn(FrameworkElement title)
355         {
356             TranslateTransform trans = new TranslateTransform();
357             trans.X = 300;
358             trans.Y = -50;
359             title.RenderTransform = trans;
360 
361             var sb = new Storyboard();
362 
363             // animate the X position
364             var db = CreateDoubleAnimation(300, 0,
365                 new SineEase(), trans, TranslateTransform.XProperty, _flyInSpeed);
366             sb.Children.Add(db);
367 
368             // animate the Y position
369             db = CreateDoubleAnimation(-100, 0,
370                 new SineEase(), trans, TranslateTransform.YProperty, _flyInSpeed);
371             sb.Children.Add(db);
372 
373             sb.Begin();
374         }
375 
376         /// <summary>
377         /// Animate the previously 'flown-out' element back to its original location.
378         /// </summary>
379         public void ItemFlyIn()
380         {
381             if (_popupCanvas.Children.Count != 2)
382                 return;
383 
384             _popup.IsOpen = true;
385             _backgroundMask.Opacity = 0.0;
386 
387             Image animatedImage = _popupCanvas.Children[1] as Image;
388 
389             var sb = new Storyboard();
390 
391             // animate the X position
392             var db = CreateDoubleAnimation(_targetElementPosition.X - 100, _targetElementPosition.X,
393                 new SineEase(),
394                 _targetElementClone, Canvas.LeftProperty, _flyInSpeed);
395             sb.Children.Add(db);
396 
397             // animate the Y position
398             db = CreateDoubleAnimation(_targetElementPosition.Y - 50, _targetElementPosition.Y,
399                 new SineEase(),
400                 _targetElementClone, Canvas.TopProperty, _flyInSpeed);
401             sb.Children.Add(db);
402 
403             sb.Completed += (s, e) =>
404             {
405                 // when the animation has finished, hide the popup once more
406                 _popup.IsOpen = false;
407 
408                 // restore the element we have animated
409                 _targetElement.Opacity = 1.0;
410 
411                 // and get rid of our clone
412                 _popupCanvas.Children.Clear();
413             };
414 
415             sb.Begin();
416         }
417 
418 
419         /// <summary>
420         /// Animate the given element so that it flies off screen, fading 
421         /// everything else that is on screen.
422         /// </summary>
423         public void ItemFlyOut(FrameworkElement element, Action action)
424         {
425             _targetElement = element;
426             var rootElement = Application.Current.RootVisual as FrameworkElement;
427 
428             _backgroundMask = new Rectangle()
429             {
430                 Fill = new SolidColorBrush(Colors.Black),
431                 Opacity = 0.0,
432                 Width = rootElement.ActualWidth,
433                 Height = rootElement.ActualHeight
434             };
435             _popupCanvas.Children.Add(_backgroundMask);
436 
437             _targetElementClone = new Image()
438             {
439                 Source = new WriteableBitmap(element, null)
440             };
441             _popupCanvas.Children.Add(_targetElementClone);
442 
443             _targetElementPosition = element.GetRelativePosition(rootElement);
444             Canvas.SetTop(_targetElementClone, _targetElementPosition.Y);
445             Canvas.SetLeft(_targetElementClone, _targetElementPosition.X);
446 
447             var sb = new Storyboard();
448 
449             // animate the X position
450             var db = CreateDoubleAnimation(_targetElementPosition.X, _targetElementPosition.X + 500,
451                 new SineEase() { EasingMode = EasingMode.EaseIn },
452                 _targetElementClone, Canvas.LeftProperty, _flyOutSpeed);
453             sb.Children.Add(db);
454 
455             // animate the Y position
456             db = CreateDoubleAnimation(_targetElementPosition.Y, _targetElementPosition.Y + 50,
457                 new SineEase() { EasingMode = EasingMode.EaseOut },
458                 _targetElementClone, Canvas.TopProperty, _flyOutSpeed);
459             sb.Children.Add(db);
460 
461             // fade out the other elements
462             db = CreateDoubleAnimation(0, 1,
463                 null, _backgroundMask, UIElement.OpacityProperty, _flyOutSpeed);
464             sb.Children.Add(db);
465 
466             sb.Completed += (s, e2) =>
467             {
468                 action();
469 
470                 // hide the popup, by placing a task on the dispatcher queue, this
471                 // should be executed after the navigation has occurred
472                 element.Dispatcher.BeginInvoke(() =>
473                 {
474                     _popup.IsOpen = false;
475                 });
476             };
477 
478             // hide the element we have 'cloned' into the popup
479             element.Opacity = 0.0;
480 
481             // open the popup
482             _popup.IsOpen = true;
483 
484             // begin the animation
485             sb.Begin();
486         }
487 
488         public static DoubleAnimation CreateDoubleAnimation(double from, double to, IEasingFunction easing,
489           DependencyObject target, object propertyPath, TimeSpan duration)
490         {
491             var db = new DoubleAnimation();
492             db.To = to;
493             db.From = from;
494             db.EasingFunction = easing;
495             db.Duration = duration;
496             Storyboard.SetTarget(db, target);
497             Storyboard.SetTargetProperty(db, new PropertyPath(propertyPath));
498             return db;
499         }
500     }
501 
502 
503     public class VisualTreeAdapter : ILinqTree<DependencyObject>
504     {
505         private DependencyObject _item;
506 
507         public VisualTreeAdapter(DependencyObject item)
508         {
509             _item = item;
510         }
511 
512         public IEnumerable<DependencyObject> Children()
513         {
514             int childrenCount = VisualTreeHelper.GetChildrenCount(_item);
515             for (int i = 0; i < childrenCount; i++)
516             {
517                 yield return VisualTreeHelper.GetChild(_item, i);
518             }
519         }
520 
521         public DependencyObject Parent
522         {
523             get
524             {
525                 return VisualTreeHelper.GetParent(_item);
526             }
527         }
528     }
529 
530     public interface ILinqTree<T>
531     {
532         IEnumerable<T> Children();
533 
534         T Parent { get; }
535     }
536 
537     public static class TreeExtensions
538     {
539         /// <summary>
540         /// Returns a collection of descendant elements.
541         /// </summary>
542         public static IEnumerable<DependencyObject> Descendants(this DependencyObject item)
543         {
544             ILinqTree<DependencyObject> adapter = new VisualTreeAdapter(item);
545             foreach (var child in adapter.Children())
546             {
547                 yield return child;
548 
549                 foreach (var grandChild in child.Descendants())
550                 {
551                     yield return grandChild;
552                 }
553             }
554         }
555 
556         /// <summary>
557         /// Returns a collection containing this element and all descendant elements.
558         /// </summary>
559         public static IEnumerable<DependencyObject> DescendantsAndSelf(this DependencyObject item)
560         {
561             yield return item;
562 
563             foreach (var child in item.Descendants())
564             {
565                 yield return child;
566             }
567         }
568 
569         /// <summary>
570         /// Returns a collection of ancestor elements.
571         /// </summary>
572         public static IEnumerable<DependencyObject> Ancestors(this DependencyObject item)
573         {
574             ILinqTree<DependencyObject> adapter = new VisualTreeAdapter(item);
575 
576             var parent = adapter.Parent;
577             while (parent != null)
578             {
579                 yield return parent;
580                 adapter = new VisualTreeAdapter(parent);
581                 parent = adapter.Parent;
582             }
583         }
584 
585         /// <summary>
586         /// Returns a collection containing this element and all ancestor elements.
587         /// </summary>
588         public static IEnumerable<DependencyObject> AncestorsAndSelf(this DependencyObject item)
589         {
590             yield return item;
591 
592             foreach (var ancestor in item.Ancestors())
593             {
594                 yield return ancestor;
595             }
596         }
597 
598         /// <summary>
599         /// Returns a collection of child elements.
600         /// </summary>
601         public static IEnumerable<DependencyObject> Elements(this DependencyObject item)
602         {
603             ILinqTree<DependencyObject> adapter = new VisualTreeAdapter(item);
604             foreach (var child in adapter.Children())
605             {
606                 yield return child;
607             }
608         }
609 
610         /// <summary>
611         /// Returns a collection of the sibling elements before this node, in document order.
612         /// </summary>
613         public static IEnumerable<DependencyObject> ElementsBeforeSelf(this DependencyObject item)
614         {
615             if (item.Ancestors().FirstOrDefault() == null)
616                 yield break;
617             foreach (var child in item.Ancestors().First().Elements())
618             {
619                 if (child.Equals(item))
620                     break;
621                 yield return child;
622             }
623         }
624 
625         /// <summary>
626         /// Returns a collection of the after elements after this node, in document order.
627         /// </summary>
628         public static IEnumerable<DependencyObject> ElementsAfterSelf(this DependencyObject item)
629         {
630             if (item.Ancestors().FirstOrDefault() == null)
631                 yield break;
632             bool afterSelf = false;
633             foreach (var child in item.Ancestors().First().Elements())
634             {
635                 if (afterSelf)
636                     yield return child;
637 
638                 if (child.Equals(item))
639                     afterSelf = true;
640             }
641         }
642 
643         /// <summary>
644         /// Returns a collection containing this element and all child elements.
645         /// </summary>
646         public static IEnumerable<DependencyObject> ElementsAndSelf(this DependencyObject item)
647         {
648             yield return item;
649 
650             foreach (var child in item.Elements())
651             {
652                 yield return child;
653             }
654         }
655 
656         /// <summary>
657         /// Returns a collection of descendant elements which match the given type.
658         /// </summary>
659         public static IEnumerable<DependencyObject> Descendants<T>(this DependencyObject item)
660         {
661             return item.Descendants().Where(i => i is T).Cast<DependencyObject>();
662         }
663 
664         /// <summary>
665         /// Returns a collection of the sibling elements before this node, in document order
666         /// which match the given type.
667         /// </summary>
668         public static IEnumerable<DependencyObject> ElementsBeforeSelf<T>(this DependencyObject item)
669         {
670             return item.ElementsBeforeSelf().Where(i => i is T).Cast<DependencyObject>();
671         }
672 
673         /// <summary>
674         /// Returns a collection of the after elements after this node, in document order
675         /// which match the given type.
676         /// </summary>
677         public static IEnumerable<DependencyObject> ElementsAfterSelf<T>(this DependencyObject item)
678         {
679             return item.ElementsAfterSelf().Where(i => i is T).Cast<DependencyObject>();
680         }
681 
682         /// <summary>
683         /// Returns a collection containing this element and all descendant elements
684         /// which match the given type.
685         /// </summary>
686         public static IEnumerable<DependencyObject> DescendantsAndSelf<T>(this DependencyObject item)
687         {
688             return item.DescendantsAndSelf().Where(i => i is T).Cast<DependencyObject>();
689         }
690 
691         /// <summary>
692         /// Returns a collection of ancestor elements which match the given type.
693         /// </summary>
694         public static IEnumerable<DependencyObject> Ancestors<T>(this DependencyObject item)
695         {
696             return item.Ancestors().Where(i => i is T).Cast<DependencyObject>();
697         }
698 
699         /// <summary>
700         /// Returns a collection containing this element and all ancestor elements
701         /// which match the given type.
702         /// </summary>
703         public static IEnumerable<DependencyObject> AncestorsAndSelf<T>(this DependencyObject item)
704         {
705             return item.AncestorsAndSelf().Where(i => i is T).Cast<DependencyObject>();
706         }
707 
708         /// <summary>
709         /// Returns a collection of child elements which match the given type.
710         /// </summary>
711         public static IEnumerable<DependencyObject> Elements<T>(this DependencyObject item)
712         {
713             return item.Elements().Where(i => i is T).Cast<DependencyObject>();
714         }
715 
716         /// <summary>
717         /// Returns a collection containing this element and all child elements.
718         /// which match the given type.
719         /// </summary>
720         public static IEnumerable<DependencyObject> ElementsAndSelf<T>(this DependencyObject item)
721         {
722             return item.ElementsAndSelf().Where(i => i is T).Cast<DependencyObject>();
723         }
724 
725     }
726 
727     public static class EnumerableTreeExtensions
728     {
729         /// <summary>
730         /// Applies the given function to each of the items in the supplied
731         /// IEnumerable.
732         /// </summary>
733         private static IEnumerable<DependencyObject> DrillDown(this IEnumerable<DependencyObject> items,
734             Func<DependencyObject, IEnumerable<DependencyObject>> function)
735         {
736             foreach (var item in items)
737             {
738                 foreach (var itemChild in function(item))
739                 {
740                     yield return itemChild;
741                 }
742             }
743         }
744 
745         /// <summary>
746         /// Applies the given function to each of the items in the supplied
747         /// IEnumerable, which match the given type.
748         /// </summary>
749         public static IEnumerable<DependencyObject> DrillDown<T>(this IEnumerable<DependencyObject> items,
750             Func<DependencyObject, IEnumerable<DependencyObject>> function)
751             where T : DependencyObject
752         {
753             foreach (var item in items)
754             {
755                 foreach (var itemChild in function(item))
756                 {
757                     if (itemChild is T)
758                     {
759                         yield return (T)itemChild;
760                     }
761                 }
762             }
763         }
764 
765         /// <summary>
766         /// Returns a collection of descendant elements.
767         /// </summary>
768         public static IEnumerable<DependencyObject> Descendants(this IEnumerable<DependencyObject> items)
769         {
770             return items.DrillDown(i => i.Descendants());
771         }
772 
773         /// <summary>
774         /// Returns a collection containing this element and all descendant elements.
775         /// </summary>
776         public static IEnumerable<DependencyObject> DescendantsAndSelf(this IEnumerable<DependencyObject> items)
777         {
778             return items.DrillDown(i => i.DescendantsAndSelf());
779         }
780 
781         /// <summary>
782         /// Returns a collection of ancestor elements.
783         /// </summary>
784         public static IEnumerable<DependencyObject> Ancestors(this IEnumerable<DependencyObject> items)
785         {
786             return items.DrillDown(i => i.Ancestors());
787         }
788 
789         /// <summary>
790         /// Returns a collection containing this element and all ancestor elements.
791         /// </summary>
792         public static IEnumerable<DependencyObject> AncestorsAndSelf(this IEnumerable<DependencyObject> items)
793         {
794             return items.DrillDown(i => i.AncestorsAndSelf());
795         }
796 
797         /// <summary>
798         /// Returns a collection of child elements.
799         /// </summary>
800         public static IEnumerable<DependencyObject> Elements(this IEnumerable<DependencyObject> items)
801         {
802             return items.DrillDown(i => i.Elements());
803         }
804 
805         /// <summary>
806         /// Returns a collection containing this element and all child elements.
807         /// </summary>
808         public static IEnumerable<DependencyObject> ElementsAndSelf(this IEnumerable<DependencyObject> items)
809         {
810             return items.DrillDown(i => i.ElementsAndSelf());
811         }
812 
813         /// <summary>
814         /// Returns a collection of descendant elements which match the given type.
815         /// </summary>
816         public static IEnumerable<DependencyObject> Descendants<T>(this IEnumerable<DependencyObject> items)
817             where T : DependencyObject
818         {
819             return items.DrillDown<T>(i => i.Descendants());
820         }
821 
822         /// <summary>
823         /// Returns a collection containing this element and all descendant elements.
824         /// which match the given type.
825         /// </summary>
826         public static IEnumerable<DependencyObject> DescendantsAndSelf<T>(this IEnumerable<DependencyObject> items)
827             where T : DependencyObject
828         {
829             return items.DrillDown<T>(i => i.DescendantsAndSelf());
830         }
831 
832         /// <summary>
833         /// Returns a collection of ancestor elements which match the given type.
834         /// </summary>
835         public static IEnumerable<DependencyObject> Ancestors<T>(this IEnumerable<DependencyObject> items)
836             where T : DependencyObject
837         {
838             return items.DrillDown<T>(i => i.Ancestors());
839         }
840 
841         /// <summary>
842         /// Returns a collection containing this element and all ancestor elements.
843         /// which match the given type.
844         /// </summary>
845         public static IEnumerable<DependencyObject> AncestorsAndSelf<T>(this IEnumerable<DependencyObject> items)
846             where T : DependencyObject
847         {
848             return items.DrillDown<T>(i => i.AncestorsAndSelf());
849         }
850 
851         /// <summary>
852         /// Returns a collection of child elements which match the given type.
853         /// </summary>
854         public static IEnumerable<DependencyObject> Elements<T>(this IEnumerable<DependencyObject> items)
855             where T : DependencyObject
856         {
857             return items.DrillDown<T>(i => i.Elements());
858         }
859 
860         /// <summary>
861         /// Returns a collection containing this element and all child elements.
862         /// which match the given type.
863         /// </summary>
864         public static IEnumerable<DependencyObject> ElementsAndSelf<T>(this IEnumerable<DependencyObject> items)
865             where T : DependencyObject
866         {
867             return items.DrillDown<T>(i => i.ElementsAndSelf());
868         }
869     }
MetroInMotion.cs

使用的时候只需要这样

<toolkit:HubTile local:MetroInMotion.Tilt="1" Grid.Row="1" Grid.Column="1" Background="Red" Source="Assets/Tiles/FlipCycleTileSmall.png" Title="Metro" Message="This is Metro in App"/>

 

高级的磁贴

现在又说回开始菜单中的磁贴,在StandardTileData的属性中有一个Count专门表达这个App存在的通知数量,但是这个属性在后来的动态磁贴出现后而变得很少用(如下图左1),这部分内容并不是取代Count属性的动态磁贴的实现,而是关注另外个内置应用的磁贴——人脉(下图中间和右2)

这里的人脉磁贴需要用到之前提过的动画效果,源码不是我编写的,我只是在网上找到老外写了那么的一个控件,cs部分的注释已经加了,xmal的由于基础不好现在还没看得明白,代码全部都铺上来,效果如下图

 

 1     public class PeopleHubTileData : INotifyPropertyChanged  
 2     {
 3         private ImageSource _ImageFront;
 4         public ImageSource ImageFront
 5         {
 6             get
 7             {
 8                 return _ImageFront;
 9             }
10             set
11             {
12                 if (value != _ImageFront)
13                 {
14                     _ImageFront = value;
15                     NotifyPropertyChanged("ImageFront");
16                 }
17             }
18         }
19 
20         private ImageSource _ImageBack;
21         public ImageSource ImageBack
22         {
23             get
24             {
25                 return _ImageBack;
26             }
27             set
28             {
29                 if (value != _ImageBack)
30                 {
31                     _ImageBack = value;
32                     NotifyPropertyChanged("ImageBack");
33                 }
34             }
35         }
36 
37         private Stretch _ImageStretch;
38         public Stretch ImageStretch
39         {
40             get
41             {
42                 return _ImageStretch;
43             }
44             set
45             {
46                 if (value != _ImageStretch)
47                 {
48                     _ImageStretch = value;
49                     NotifyPropertyChanged("ImageStretch");
50                 }
51             }
52         }
53 
54 
55       
56 
57         public event PropertyChangedEventHandler PropertyChanged;
58         private void NotifyPropertyChanged(String propertyName)
59         {
60             PropertyChangedEventHandler handler = PropertyChanged;
61             if (null != handler)
62             {
63                 handler(this, new PropertyChangedEventArgs(propertyName));
64             }
65         }
66     }
PepoleHubTileData

 

 1     public class Tiles : DependencyObject
 2     {
 3         public Tiles()
 4         {
 5             this.CenterOfRotationY = 0.5;
 6         }
 7         public Tiles(object item)
 8             : this()
 9         {
10             this.TileData = item;
11         }
12         public object TileData { get; set; }
13 
14         public double CenterOfRotationY { get; set; }
15         public double ZIndex
16         {
17             get { return (int)GetValue(ZIndexProperty); }
18             set { SetValue(ZIndexProperty, value); }
19         }
20         public static DependencyProperty ZIndexProperty = DependencyProperty.Register("ZIndex", typeof(int), typeof(Tiles), new PropertyMetadata(0));
21         public double RotationX
22         {
23             get { return (double)GetValue(RotationXProperty); }
24             set { SetValue(RotationXProperty, value); }
25         }
26         public static DependencyProperty RotationXProperty = DependencyProperty.Register("RotationX", typeof(double), typeof(Tiles), new PropertyMetadata(0.0));
27        
28 
29       
30     }
Tiles

 

  1     public class PeopleHubTile : ContentControl
  2     {
  3         #region Member variables
  4         private int LastAnimatedTile = 0;
  5         /// <summary>
  6         /// 大磁贴起始位置选择完毕,可以开始制造大磁贴
  7         /// </summary>
  8         private bool isBigTileAnimationStarted = false;
  9         /// <summary>
 10         /// 表明给大磁贴选择了图片
 11         /// </summary>
 12         private bool isBitImageSelected = false;
 13         /// <summary>
 14         /// 大磁贴图片的索引
 15         /// </summary>
 16         private int BitImageSelectedIndex = 0;
 17         /// <summary>
 18         /// 累计翻动大磁贴时已经翻动了小磁贴的数目
 19         /// </summary>
 20         private int TileAnimateIndex = 0;
 21         private int TileAnimationCount = 0;
 22         /// <summary>
 23         /// 所有磁贴进入就绪状态,可以开始选取大磁贴的起始位置
 24         /// </summary>
 25         private bool isReadyForBigTile = false;
 26         private Random RandomTile = new Random();
 27         private DispatcherTimer dispatcherTimer = new DispatcherTimer();
 28         private List<String> ImageUrl = new List<string>() 
 29         {
 30             "/Themes/Images/1.jpg",
 31             "/Themes/Images/13.jpg",
 32             "/Themes/Images/14.jpg",
 33             "/Themes/Images/15.jpg",
 34             "/Themes/Images/16.jpg",
 35             "/Themes/Images/17.jpg",
 36             "/Themes/Images/18.jpg",
 37             "/Themes/Images/19.jpg",
 38             "/Themes/Images/2.jpg",
 39             "/Themes/Images/20.jpg",
 40             "/Themes/Images/21.jpg",
 41             "/Themes/Images/3.jpg",
 42              
 43         };
 44 
 45 
 46 
 47         private ObservableCollection<Tiles> dataItems = new ObservableCollection<Tiles>()
 48         {
 49           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/1.jpg", UriKind.RelativeOrAbsolute)) }),
 50           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/2.jpg", UriKind.RelativeOrAbsolute)) }),
 51           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/13.jpg", UriKind.RelativeOrAbsolute)) }),
 52           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/14.jpg", UriKind.RelativeOrAbsolute)) }),
 53           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/15.jpg", UriKind.RelativeOrAbsolute)) }),
 54           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/16.jpg", UriKind.RelativeOrAbsolute)) }),
 55           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/17.jpg", UriKind.RelativeOrAbsolute)) }),
 56           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/18.jpg", UriKind.RelativeOrAbsolute)) }),
 57           new Tiles(new PeopleHubTileData(){ ImageFront = new BitmapImage(new Uri("/Themes/Images/19.jpg", UriKind.RelativeOrAbsolute)) }),
 58         };
 59         #endregion
 60 
 61         #region Constructor
 62         public PeopleHubTile()
 63         {
 64             DefaultStyleKey = typeof(PeopleHubTile);
 65             Loaded += PeopleHubTile_Loaded;
 66 
 67         }
 68         #endregion
 69 
 70         #region Methods
 71         ListBox ItemsListBox;
 72         void PeopleHubTile_Loaded(object sender, RoutedEventArgs e)
 73         {
 74             ///在generic中获取ListBox 附上各个Tilt在ListBox中
 75             ItemsListBox = this.GetTemplateChild("ItemsListBox") as ListBox;
 76             this.ItemsListBox.ItemsSource = dataItems;
 77             //开启定时更换tile的任务
 78             dispatcherTimer.Interval = TimeSpan.FromSeconds(2);
 79             dispatcherTimer.Tick += dispatcherTimer_Tick;
 80             dispatcherTimer.Start();
 81         }
 82 
 83         void dispatcherTimer_Tick(object sender, EventArgs e)
 84         {
 85             //计数,如果是9个则尝试启动大磁贴
 86             TileAnimationCount++;
 87             if (TileAnimationCount > 9 && isReadyForBigTile == false)
 88             {
 89                 TileAnimationCount = 0;
 90                 isReadyForBigTile = true;
 91 
 92             }
 93 
 94 
 95             int AnimateItem = 0;
 96             Tiles AnimateTile = null;
 97             //未启动大磁贴的操作
 98             if (!isBigTileAnimationStarted)
 99             {
100                 AnimateItem = RandomTile.Next(this.dataItems.Count);
101                 AnimateTile = this.dataItems[AnimateItem];
102 
103                 ///尝试启动大磁贴 并且当前是抽到变换的磁贴是允许作为大磁贴的第一个磁贴
104                 ///它变换大磁贴时是从大磁贴的左上 右上 左下 右下来变换
105                 if (isReadyForBigTile && (AnimateItem == 0 || AnimateItem == 1 || AnimateItem == 3 || AnimateItem == 4))
106                 {
107                     LastAnimatedTile = AnimateItem;
108                     isBigTileAnimationStarted = true;
109                     TileAnimateIndex = 0;
110                    
111                 }
112 
113                 ///用ZIndex来区分正面和反面
114                 /// Animate small tiles
115                 if (AnimateTile.ZIndex == 0)
116                 {
117                     //back tile
118                     PeopleHubTileData ItemData = AnimateTile.TileData as PeopleHubTileData;
119 
120                     int newImage = RandomTile.Next(ImageUrl.Count);
121                     if (RandomTile.Next(20) > 5)
122                         ItemData.ImageBack = new BitmapImage(new Uri(ImageUrl[newImage], UriKind.RelativeOrAbsolute));
123                     else
124                         ItemData.ImageBack = new BitmapImage(new Uri("", UriKind.RelativeOrAbsolute));
125                 }
126                 else if (AnimateTile.ZIndex != 0)
127                 {
128                     //front tile
129                     PeopleHubTileData ItemData = AnimateTile.TileData as PeopleHubTileData;
130 
131                     int newImage = RandomTile.Next(ImageUrl.Count);
132                     if (RandomTile.Next(20) > 5)
133                         ItemData.ImageFront = new BitmapImage(new Uri(ImageUrl[newImage], UriKind.RelativeOrAbsolute));
134                     else
135                         ItemData.ImageFront = new BitmapImage(new Uri("", UriKind.RelativeOrAbsolute));
136 
137 
138                 }
139 
140 
141             }
142 
143 
144             ///已经启用大磁贴 
145             else if (isBigTileAnimationStarted && TileAnimateIndex < 4)
146             {
147 
148                 int[] LastTiles = new int[4];
149                 //按照大磁贴其实位置来选出大磁贴所占用的小磁贴的索引
150                 switch (LastAnimatedTile)
151                 {
152                     case 0:
153                         LastTiles = new int[4] { 0, 1, 3, 4 };
154                         break;
155                     case 1:
156                         LastTiles = new int[4] { 1, 2, 4, 5 };
157                         break;
158                     case 3:
159                         LastTiles = new int[4] { 3, 4, 6, 7 };
160                         break;
161                     case 4:
162                         LastTiles = new int[4] { 4, 5, 7, 8 };
163                         break;
164                     default:
165                         break;
166 
167                 }
168 
169 
170               
171                 AnimateTile = this.dataItems[LastTiles[TileAnimateIndex]];
172                 ///还没有生成大磁贴所用的图片时
173                 if (!isBitImageSelected)
174                 {
175                     isBitImageSelected = true;
176                     BitImageSelectedIndex = RandomTile.Next(ImageUrl.Count);
177                 }
178                 ///bmpWB是直接从资源列表中拿的图片
179                 BitmapImage bmpWB = new BitmapImage(new Uri(ImageUrl[BitImageSelectedIndex], UriKind.RelativeOrAbsolute));
180                 ///最终写到磁贴上的部分图片
181                 WriteableBitmap ImageWB = new WriteableBitmap(bmpWB.PixelWidth, bmpWB.PixelHeight);
182                 bmpWB.CreateOptions = BitmapCreateOptions.None;
183                 ///整幅大磁贴的图片
184                 WriteableBitmap imageBitMap = new WriteableBitmap(bmpWB);
185 
186                 switch (TileAnimateIndex)
187                 {
188                     case 0:
189 
190                         ImageWB = GetCropImage(imageBitMap, 0, 0, imageBitMap.PixelWidth / 2, imageBitMap.PixelHeight / 2);
191 
192                         break;
193                     case 1:
194 
195                         ImageWB = GetCropImage(imageBitMap, imageBitMap.PixelWidth / 2, 0, imageBitMap.PixelWidth / 2, imageBitMap.PixelHeight / 2);
196                         break;
197                     case 2:
198 
199                         ImageWB = GetCropImage(imageBitMap, 0, imageBitMap.PixelHeight / 2, imageBitMap.PixelWidth / 2, imageBitMap.PixelHeight / 2);
200 
201 
202 
203                         break;
204                     case 3:
205 
206                         ImageWB = GetCropImage(imageBitMap, imageBitMap.PixelWidth / 2, imageBitMap.PixelHeight / 2, imageBitMap.PixelWidth / 2, imageBitMap.PixelHeight / 2);
207                         break;
208                     default:
209                         break;
210 
211                 }
212                 ///通过累计数目来判断大磁贴是否完成
213                 TileAnimateIndex++;
214                 if (TileAnimateIndex > 3)
215                 {
216                     isBigTileAnimationStarted = false;
217                     isReadyForBigTile = false;
218                     isBitImageSelected = false;
219                 }
220 
221 
222                 //animate part of big tiles
223                 if (AnimateTile.ZIndex == 0)
224                 {
225                     //back tile
226                     PeopleHubTileData ItemData = AnimateTile.TileData as PeopleHubTileData;
227 
228                     ItemData.ImageBack = ImageWB;
229 
230                 }
231                 else if (AnimateTile.ZIndex != 0)
232                 {
233                     //front tile
234                     PeopleHubTileData ItemData = AnimateTile.TileData as PeopleHubTileData;
235 
236                     ItemData.ImageFront = ImageWB;
237                 }
238 
239 
240             }
241             //tile animation 
242             Storyboard MyStory = new Storyboard();
243             DoubleAnimation MyDouble = new DoubleAnimation();
244             MyDouble.From = AnimateTile.RotationX;
245             MyDouble.To = AnimateTile.RotationX + 180;
246             MyDouble.Duration = TimeSpan.FromSeconds(0.5);
247             Storyboard.SetTarget(MyDouble, AnimateTile);
248             Storyboard.SetTargetProperty(MyDouble, new PropertyPath(Tiles.RotationXProperty));
249             MyStory.Children.Add(MyDouble);
250 
251             ObjectAnimationUsingKeyFrames MyObject = new ObjectAnimationUsingKeyFrames();
252             DiscreteObjectKeyFrame MyKeyFrame = new DiscreteObjectKeyFrame();
253             MyKeyFrame.KeyTime = TimeSpan.FromSeconds(0);
254             MyKeyFrame.Value = AnimateTile.ZIndex;
255             MyObject.KeyFrames.Add(MyKeyFrame);
256            
257             MyKeyFrame = new DiscreteObjectKeyFrame();
258             MyKeyFrame.KeyTime = TimeSpan.FromSeconds(0.3);
259             MyKeyFrame.Value = (AnimateTile.ZIndex == 0) ? 1 : 0;
260             MyObject.KeyFrames.Add(MyKeyFrame);
261             Storyboard.SetTarget(MyObject, AnimateTile);
262             Storyboard.SetTargetProperty(MyObject, new PropertyPath(Tiles.ZIndexProperty));
263             MyStory.Children.Add(MyObject);
264             MyStory.Begin();
265 
266 
267 
268         }
269 
270         /// <summary>
271         /// 利用数组copy,通过计算位图的位置来切割出部分的图片
272         /// </summary>
273         /// <param name="aBitmapSource"></param>
274         /// <param name="XPoint"></param>
275         /// <param name="YPoint"></param>
276         /// <param name="aWidth"></param>
277         /// <param name="aHeight"></param>
278         /// <returns></returns>
279         private static WriteableBitmap GetCropImage(WriteableBitmap aBitmapSource, int XPoint, int YPoint, int aWidth, int aHeight)
280         {
281             var SourceWidth = aBitmapSource.PixelWidth;
282             var result = new WriteableBitmap(aWidth, aHeight);
283             for (var x = 0; x < aHeight - 1; x++)
284             {
285                 var Index = XPoint + (YPoint + x) * SourceWidth;
286                 var FinalIndex = x * aWidth;
287                 Array.Copy(aBitmapSource.Pixels, Index, result.Pixels, FinalIndex, aWidth);
288 
289 
290             }
291             return result;
292         }
293         #endregion
294 
295         #region OnApplyTemplate
296         public override void OnApplyTemplate()
297         {
298             base.OnApplyTemplate();
299         }
300         #endregion
301     }
PepoleHubTile

 

 1 <ResourceDictionary
 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4     xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
 5     xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
 6     xmlns:local="clr-namespace:PeopleHubTileEx">
 7     
 8     <DataTemplate x:Key="DataTemplatePeopleHubTile">
 9         <Grid x:Name="TileGrid" Height="80" Width="80" >
10             <Grid.Projection>
11                 <PlaneProjection RotationX="{Binding RotationX}" CenterOfRotationY="{Binding CenterOfRotationX}">
12                 </PlaneProjection>
13             </Grid.Projection>
14             <Grid x:Name="BackGrid" Canvas.ZIndex="{Binding ZIndex}" RenderTransformOrigin="0.5,0.5">
15                 <Grid.RenderTransform>
16                     <CompositeTransform ScaleY="-1"/>
17                 </Grid.RenderTransform>
18                 <Grid.Background>
19                     <SolidColorBrush Color="Green"></SolidColorBrush>
20                 </Grid.Background>
21                 <Image Source="{Binding TileData.ImageBack}"  Stretch="Fill" />
22             </Grid>
23             <Grid x:Name="FrontGrid">
24                 <Grid.Background>
25                     <SolidColorBrush Color="Green"></SolidColorBrush>
26                 </Grid.Background>
27                 <Image  Source="{Binding TileData.ImageFront}"  Stretch="Fill" >
28 
29                 </Image>
30             </Grid>
31         </Grid>
32     </DataTemplate>
33   
34     <Style TargetType="local:PeopleHubTile">
35 
36         <Setter Property="Template">
37             <Setter.Value>
38                 <ControlTemplate TargetType="local:PeopleHubTile">
39                     <Grid>
40                         <ListBox Name="ItemsListBox" Width="240" Height="240"
41                  ScrollViewer.HorizontalScrollBarVisibility="Disabled"
42                  ScrollViewer.VerticalScrollBarVisibility="Disabled"
43                  ItemTemplate="{StaticResource DataTemplatePeopleHubTile}">
44                             <ListBox.ItemsPanel>
45                                 <ItemsPanelTemplate>
46                                     <toolkit:WrapPanel ItemHeight="80" ItemWidth="80" Orientation="Horizontal">
47 
48                                     </toolkit:WrapPanel>
49                                 </ItemsPanelTemplate>
50                             </ListBox.ItemsPanel>
51                         </ListBox>
52                        
53                     </Grid>
54 
55                 </ControlTemplate>
56             </Setter.Value>
57         </Setter>
58     </Style>
59 </ResourceDictionary>
generic.xaml

使用的时候只需要以下面的形式则可。

            <PeopleHubTileControl:PeopleHubTile  VerticalAlignment="Center">
                
            </PeopleHubTileControl:PeopleHubTile>     

 

1楼shaomeng
支持一下!

文章评论

Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
一个程序员的时间管理
一个程序员的时间管理
为什么程序员都是夜猫子
为什么程序员都是夜猫子
10个调试和排错的小建议
10个调试和排错的小建议
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
Java程序员必看电影
Java程序员必看电影
每天工作4小时的程序员
每天工作4小时的程序员
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
总结2014中国互联网十大段子
总结2014中国互联网十大段子
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
程序员和编码员之间的区别
程序员和编码员之间的区别
我的丈夫是个程序员
我的丈夫是个程序员
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序员必看的十大电影
程序员必看的十大电影
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
老程序员的下场
老程序员的下场
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
旅行,写作,编程
旅行,写作,编程
鲜为人知的编程真相
鲜为人知的编程真相
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
程序员都该阅读的书
程序员都该阅读的书
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
漫画:程序员的工作
漫画:程序员的工作
中美印日四国程序员比较
中美印日四国程序员比较
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
我是如何打败拖延症的
我是如何打败拖延症的
程序员应该关注的一些事儿
程序员应该关注的一些事儿
如何成为一名黑客
如何成为一名黑客
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
代码女神横空出世
代码女神横空出世
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
 程序员的样子
程序员的样子
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有