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

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

开始菜单的磁贴

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

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

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

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

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

在开始菜单中的磁贴分两类,一类是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";

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

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

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

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

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

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

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

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

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

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

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

在需要使用该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是在磁贴背面

 

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

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

运行的时候会发现磁贴是贴在了页面上了,但是手点击上去就没有了开始菜单中的那种倾斜效果,这个磁贴的倾斜效果是这个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的效果不是很明显,而且有限制,有一些控件虽然用上了但也没有倾斜的效果。在网上查看资料时发现有个老外也写了一个倾斜效果,效果比微软提供的要明显,而且还可以调节倾斜的角度。两个类的代码如下

WinPhone学习笔记(四)——磁贴
  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
WinPhone学习笔记(四)——磁贴
  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)

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

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

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

 

WinPhone学习笔记(四)——磁贴
 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

 

WinPhone学习笔记(四)——磁贴
 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

 

WinPhone学习笔记(四)——磁贴
  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

 

WinPhone学习笔记(四)——磁贴
 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>     

 

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

上一篇:十三届大学生数学竞赛第四题:轮换对称加球坐标华莱士公式将计算量化简到最小


下一篇:【转】遇见和缘分