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>     

 

你可能感兴趣的:(学习笔记)