RelativeAnimatingContentControl.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  4. // All other rights reserved.
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Linq;
  9. using System.Windows;
  10. using System.Windows.Controls;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Animation;
  13. // This is a very special primitive control that works around a limitation in
  14. // the core animation subsystem of Silverlight: there is no way to declare in
  15. // VSM states relative properties, such as animating from 0 to 33% the width of
  16. // the control, using double animations for translation.
  17. //
  18. // It's a tough problem to solve property, but this primitive, unsupported
  19. // control does offer a solution based on magic numbers that still allows a
  20. // designer to make alterations to their animation values to present their
  21. // vision for custom templates.
  22. //
  23. // This is instrumental in offering a Windows Phone ProgressBar implementation
  24. // that uses the render thread instead of animating UI thread-only properties.
  25. //
  26. // For questions, please see
  27. // http://www.jeff.wilcox.name/performanceprogressbar/
  28. //
  29. // This control is licensed Ms-PL and as such comes with no warranties or
  30. // official support.
  31. //
  32. // Style Note
  33. // - - -
  34. // The style that must be used with this is present at the bottom of this file.
  35. //
  36. namespace WindowsPhone.Recipes.Push.Client.Controls
  37. {
  38. /// <summary>
  39. /// A very specialized primitive control that works around a specific visual
  40. /// state manager issue. The platform does not support relative sized
  41. /// translation values, and this special control walks through visual state
  42. /// animation storyboards looking for magic numbers to use as percentages.
  43. /// This control is not supported, unofficial, and is a hack in many ways.
  44. /// It is used to enable a Windows Phone native platform-style progress bar
  45. /// experience in indeterminate mode that remains performant.
  46. /// </summary>
  47. public class RelativeAnimatingContentControl : ContentControl
  48. {
  49. /// <summary>
  50. /// A simple Epsilon-style value used for trying to determine the magic
  51. /// state, if any, of a double.
  52. /// </summary>
  53. private const double SimpleDoubleComparisonEpsilon = 0.000009;
  54. /// <summary>
  55. /// The last known width of the control.
  56. /// </summary>
  57. private double _knownWidth;
  58. /// <summary>
  59. /// The last known height of the control.
  60. /// </summary>
  61. private double _knownHeight;
  62. /// <summary>
  63. /// A set of custom animation adapters used to update the animation
  64. /// storyboards when the size of the control changes.
  65. /// </summary>
  66. private List<AnimationValueAdapter> _specialAnimations;
  67. /// <summary>
  68. /// Initializes a new instance of the RelativeAnimatingContentControl
  69. /// type.
  70. /// </summary>
  71. public RelativeAnimatingContentControl()
  72. {
  73. SizeChanged += OnSizeChanged;
  74. }
  75. /// <summary>
  76. /// Handles the size changed event.
  77. /// </summary>
  78. /// <param name="sender">The source object.</param>
  79. /// <param name="e">The event arguments.</param>
  80. private void OnSizeChanged(object sender, SizeChangedEventArgs e)
  81. {
  82. if (e != null && e.NewSize.Height > 0 && e.NewSize.Width > 0)
  83. {
  84. _knownWidth = e.NewSize.Width;
  85. _knownHeight = e.NewSize.Height;
  86. Clip = new RectangleGeometry { Rect = new Rect(0, 0, _knownWidth, _knownHeight), };
  87. UpdateAnyAnimationValues();
  88. }
  89. }
  90. /// <summary>
  91. /// Walks through the known storyboards in the control's template that
  92. /// may contain magic double animation values, storing them for future
  93. /// use and updates.
  94. /// </summary>
  95. private void UpdateAnyAnimationValues()
  96. {
  97. if (_knownHeight > 0 && _knownWidth > 0)
  98. {
  99. // Initially, before any special animations have been found,
  100. // the visual state groups of the control must be explored.
  101. // By definition they must be at the implementation root of the
  102. // control, and this is designed to not walk into any other
  103. // depth.
  104. if (_specialAnimations == null)
  105. {
  106. _specialAnimations = new List<AnimationValueAdapter>();
  107. foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(this))
  108. {
  109. if (group == null)
  110. {
  111. continue;
  112. }
  113. foreach (VisualState state in group.States)
  114. {
  115. if (state != null)
  116. {
  117. Storyboard sb = state.Storyboard;
  118. if (sb != null)
  119. {
  120. // Examine all children of the storyboards,
  121. // looking for either type of double
  122. // animation.
  123. foreach (Timeline timeline in sb.Children)
  124. {
  125. DoubleAnimation da = timeline as DoubleAnimation;
  126. DoubleAnimationUsingKeyFrames dakeys = timeline as DoubleAnimationUsingKeyFrames;
  127. if (da != null)
  128. {
  129. ProcessDoubleAnimation(da);
  130. }
  131. else if (dakeys != null)
  132. {
  133. ProcessDoubleAnimationWithKeys(dakeys);
  134. }
  135. }
  136. }
  137. }
  138. }
  139. }
  140. }
  141. // Update special animation values relative to the current size.
  142. UpdateKnownAnimations();
  143. }
  144. }
  145. /// <summary>
  146. /// Walks through all special animations, updating based on the current
  147. /// size of the control.
  148. /// </summary>
  149. private void UpdateKnownAnimations()
  150. {
  151. foreach (AnimationValueAdapter adapter in _specialAnimations)
  152. {
  153. adapter.UpdateWithNewDimension(_knownWidth, _knownHeight);
  154. }
  155. }
  156. /// <summary>
  157. /// Processes a double animation with keyframes, looking for known
  158. /// special values to store with an adapter.
  159. /// </summary>
  160. /// <param name="da">The double animation using key frames instance.</param>
  161. private void ProcessDoubleAnimationWithKeys(DoubleAnimationUsingKeyFrames da)
  162. {
  163. // Look through all keyframes in the instance.
  164. foreach (DoubleKeyFrame frame in da.KeyFrames)
  165. {
  166. var d = DoubleAnimationFrameAdapter.GetDimensionFromMagicNumber(frame.Value);
  167. if (d.HasValue)
  168. {
  169. _specialAnimations.Add(new DoubleAnimationFrameAdapter(d.Value, frame));
  170. }
  171. }
  172. }
  173. /// <summary>
  174. /// Processes a double animation looking for special values.
  175. /// </summary>
  176. /// <param name="da">The double animation instance.</param>
  177. private void ProcessDoubleAnimation(DoubleAnimation da)
  178. {
  179. // Look for a special value in the To property.
  180. if (da.To.HasValue)
  181. {
  182. var d = DoubleAnimationToAdapter.GetDimensionFromMagicNumber(da.To.Value);
  183. if (d.HasValue)
  184. {
  185. _specialAnimations.Add(new DoubleAnimationToAdapter(d.Value, da));
  186. }
  187. }
  188. // Look for a special value in the From property.
  189. if (da.From.HasValue)
  190. {
  191. var d = DoubleAnimationFromAdapter.GetDimensionFromMagicNumber(da.To.Value);
  192. if (d.HasValue)
  193. {
  194. _specialAnimations.Add(new DoubleAnimationFromAdapter(d.Value, da));
  195. }
  196. }
  197. }
  198. #region Private animation updating system
  199. /// <summary>
  200. /// A selection of dimensions of interest for updating an animation.
  201. /// </summary>
  202. private enum DoubleAnimationDimension
  203. {
  204. /// <summary>
  205. /// The width (horizontal) dimension.
  206. /// </summary>
  207. Width,
  208. /// <summary>
  209. /// The height (vertical) dimension.
  210. /// </summary>
  211. Height,
  212. }
  213. /// <summary>
  214. /// A simple class designed to store information about a specific
  215. /// animation instance and its properties. Able to update the values at
  216. /// runtime.
  217. /// </summary>
  218. private abstract class AnimationValueAdapter
  219. {
  220. /// <summary>
  221. /// Gets or sets the original double value.
  222. /// </summary>
  223. protected double OriginalValue { get; set; }
  224. /// <summary>
  225. /// Initializes a new instance of the AnimationValueAdapter type.
  226. /// </summary>
  227. /// <param name="dimension">The dimension of interest for updates.</param>
  228. public AnimationValueAdapter(DoubleAnimationDimension dimension)
  229. {
  230. Dimension = dimension;
  231. }
  232. /// <summary>
  233. /// Gets the dimension of interest for the control.
  234. /// </summary>
  235. public DoubleAnimationDimension Dimension { get; private set; }
  236. /// <summary>
  237. /// Updates the original instance based on new dimension information
  238. /// from the control. Takes both and allows the subclass to make the
  239. /// decision on which ratio, values, and dimension to use.
  240. /// </summary>
  241. /// <param name="width">The width of the control.</param>
  242. /// <param name="height">The height of the control.</param>
  243. public abstract void UpdateWithNewDimension(double width, double height);
  244. }
  245. private abstract class GeneralAnimationValueAdapter<T> : AnimationValueAdapter
  246. {
  247. /// <summary>
  248. /// Stores the animation instance.
  249. /// </summary>
  250. protected T Instance { get; set; }
  251. /// <summary>
  252. /// Gets the value of the underlying property of interest.
  253. /// </summary>
  254. /// <returns>Returns the value of the property.</returns>
  255. protected abstract double GetValue();
  256. /// <summary>
  257. /// Sets the value for the underlying property of interest.
  258. /// </summary>
  259. /// <param name="newValue">The new value for the property.</param>
  260. protected abstract void SetValue(double newValue);
  261. /// <summary>
  262. /// Gets the initial value (minus the magic number portion) that the
  263. /// designer stored within the visual state animation property.
  264. /// </summary>
  265. protected double InitialValue { get; private set; }
  266. /// <summary>
  267. /// The ratio based on the original magic value, used for computing
  268. /// the updated animation property of interest when the size of the
  269. /// control changes.
  270. /// </summary>
  271. private double _ratio;
  272. /// <summary>
  273. /// Initializes a new instance of the GeneralAnimationValueAdapter
  274. /// type.
  275. /// </summary>
  276. /// <param name="d">The dimension of interest.</param>
  277. /// <param name="instance">The animation type instance.</param>
  278. public GeneralAnimationValueAdapter(DoubleAnimationDimension d, T instance)
  279. : base(d)
  280. {
  281. Instance = instance;
  282. InitialValue = StripMagicNumberOff(GetValue());
  283. _ratio = InitialValue / 100;
  284. }
  285. /// <summary>
  286. /// Approximately removes the magic number state from a value.
  287. /// </summary>
  288. /// <param name="number">The initial number.</param>
  289. /// <returns>Returns a double with an adjustment for the magic
  290. /// portion of the number.</returns>
  291. public double StripMagicNumberOff(double number)
  292. {
  293. return Dimension == DoubleAnimationDimension.Width ? number - .1 : number - .2;
  294. }
  295. /// <summary>
  296. /// Retrieves the dimension, if any, from the number. If the number
  297. /// is not magic, null is returned instead.
  298. /// </summary>
  299. /// <param name="number">The double value.</param>
  300. /// <returns>Returs a double animation dimension, if the number was
  301. /// partially magic; otherwise, returns null.</returns>
  302. public static DoubleAnimationDimension? GetDimensionFromMagicNumber(double number)
  303. {
  304. double floor = Math.Floor(number);
  305. double remainder = number - floor;
  306. if (remainder >= .1 - SimpleDoubleComparisonEpsilon && remainder <= .1 + SimpleDoubleComparisonEpsilon)
  307. {
  308. return DoubleAnimationDimension.Width;
  309. }
  310. if (remainder >= .2 - SimpleDoubleComparisonEpsilon && remainder <= .2 + SimpleDoubleComparisonEpsilon)
  311. {
  312. return DoubleAnimationDimension.Height;
  313. }
  314. return null;
  315. }
  316. /// <summary>
  317. /// Updates the animation instance based on the dimensions of the
  318. /// control.
  319. /// </summary>
  320. /// <param name="width">The width of the control.</param>
  321. /// <param name="height">The height of the control.</param>
  322. public override void UpdateWithNewDimension(double width, double height)
  323. {
  324. double size = Dimension == DoubleAnimationDimension.Width ? width : height;
  325. UpdateValue(size);
  326. }
  327. /// <summary>
  328. /// Updates the value of the property.
  329. /// </summary>
  330. /// <param name="sizeToUse">The size of interest to use with a ratio
  331. /// computation.</param>
  332. private void UpdateValue(double sizeToUse)
  333. {
  334. SetValue(sizeToUse * _ratio);
  335. }
  336. }
  337. /// <summary>
  338. /// Adapter for DoubleAnimation's To property.
  339. /// </summary>
  340. private class DoubleAnimationToAdapter : GeneralAnimationValueAdapter<DoubleAnimation>
  341. {
  342. /// <summary>
  343. /// Gets the value of the underlying property of interest.
  344. /// </summary>
  345. /// <returns>Returns the value of the property.</returns>
  346. protected override double GetValue()
  347. {
  348. return (double)Instance.To;
  349. }
  350. /// <summary>
  351. /// Sets the value for the underlying property of interest.
  352. /// </summary>
  353. /// <param name="newValue">The new value for the property.</param>
  354. protected override void SetValue(double newValue)
  355. {
  356. Instance.To = newValue;
  357. }
  358. /// <summary>
  359. /// Initializes a new instance of the DoubleAnimationToAdapter type.
  360. /// </summary>
  361. /// <param name="dimension">The dimension of interest.</param>
  362. /// <param name="instance">The instance of the animation type.</param>
  363. public DoubleAnimationToAdapter(DoubleAnimationDimension dimension, DoubleAnimation instance)
  364. : base(dimension, instance)
  365. {
  366. }
  367. }
  368. /// <summary>
  369. /// Adapter for DoubleAnimation's From property.
  370. /// </summary>
  371. private class DoubleAnimationFromAdapter : GeneralAnimationValueAdapter<DoubleAnimation>
  372. {
  373. /// <summary>
  374. /// Gets the value of the underlying property of interest.
  375. /// </summary>
  376. /// <returns>Returns the value of the property.</returns>
  377. protected override double GetValue()
  378. {
  379. return (double)Instance.From;
  380. }
  381. /// <summary>
  382. /// Sets the value for the underlying property of interest.
  383. /// </summary>
  384. /// <param name="newValue">The new value for the property.</param>
  385. protected override void SetValue(double newValue)
  386. {
  387. Instance.From = newValue;
  388. }
  389. /// <summary>
  390. /// Initializes a new instance of the DoubleAnimationFromAdapter
  391. /// type.
  392. /// </summary>
  393. /// <param name="dimension">The dimension of interest.</param>
  394. /// <param name="instance">The instance of the animation type.</param>
  395. public DoubleAnimationFromAdapter(DoubleAnimationDimension dimension, DoubleAnimation instance)
  396. : base(dimension, instance)
  397. {
  398. }
  399. }
  400. /// <summary>
  401. /// Adapter for double key frames.
  402. /// </summary>
  403. private class DoubleAnimationFrameAdapter : GeneralAnimationValueAdapter<DoubleKeyFrame>
  404. {
  405. /// <summary>
  406. /// Gets the value of the underlying property of interest.
  407. /// </summary>
  408. /// <returns>Returns the value of the property.</returns>
  409. protected override double GetValue()
  410. {
  411. return Instance.Value;
  412. }
  413. /// <summary>
  414. /// Sets the value for the underlying property of interest.
  415. /// </summary>
  416. /// <param name="newValue">The new value for the property.</param>
  417. protected override void SetValue(double newValue)
  418. {
  419. Instance.Value = newValue;
  420. }
  421. /// <summary>
  422. /// Initializes a new instance of the DoubleAnimationFrameAdapter
  423. /// type.
  424. /// </summary>
  425. /// <param name="dimension">The dimension of interest.</param>
  426. /// <param name="instance">The instance of the animation type.</param>
  427. public DoubleAnimationFrameAdapter(DoubleAnimationDimension dimension, DoubleKeyFrame frame)
  428. : base(dimension, frame)
  429. {
  430. }
  431. }
  432. #endregion
  433. }
  434. /*
  435. This is the style that should be used with the control. Make sure to define
  436. the XMLNS at the top of the style file similar to this:
  437. xmlns:unsupported="clr-namespace:WindowsPhone.Recipes.Push.Client.Controls"
  438. <!--
  439. // Performance Progress Bar
  440. // - - -
  441. // To use this progress bar at runtime, make sure to set the Style
  442. // value to this key. Since the control visually is identical to control
  443. // in the Windows Phone runtime, you will not be able to visually tell
  444. // the difference: except this style will not use the UI thread at
  445. // runtime when IsIndeterminate=true.
  446. //
  447. // <ProgressBar Style="{StaticResource PerformanceProgressBar}"
  448. // IsIndeterminate="true"/>
  449. //
  450. -->
  451. <Style x:Key="PerformanceProgressBar" TargetType="ProgressBar">
  452. <Setter Property="Foreground" Value="{StaticResource PhoneAccentBrush}"/>
  453. <Setter Property="Background" Value="{StaticResource PhoneAccentBrush}"/>
  454. <Setter Property="Maximum" Value="100"/>
  455. <Setter Property="IsHitTestVisible" Value="False"/>
  456. <Setter Property="Padding" Value="{StaticResource PhoneHorizontalMargin}"/>
  457. <Setter Property="Template">
  458. <Setter.Value>
  459. <ControlTemplate TargetType="ProgressBar">
  460. <unsupported:RelativeAnimatingContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
  461. <unsupported:RelativeAnimatingContentControl.Resources>
  462. <ExponentialEase EasingMode="EaseOut" Exponent="1" x:Key="ProgressBarEaseOut"/>
  463. <ExponentialEase EasingMode="EaseOut" Exponent="1" x:Key="ProgressBarEaseIn"/>
  464. </unsupported:RelativeAnimatingContentControl.Resources>
  465. <VisualStateManager.VisualStateGroups>
  466. <VisualStateGroup x:Name="CommonStates">
  467. <VisualState x:Name="Determinate"/>
  468. <VisualState x:Name="Indeterminate">
  469. <Storyboard RepeatBehavior="Forever" Duration="00:00:04.4">
  470. <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="IndeterminateRoot">
  471. <DiscreteObjectKeyFrame KeyTime="0">
  472. <DiscreteObjectKeyFrame.Value>
  473. <Visibility>Visible</Visibility>
  474. </DiscreteObjectKeyFrame.Value>
  475. </DiscreteObjectKeyFrame>
  476. </ObjectAnimationUsingKeyFrames>
  477. <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DeterminateRoot">
  478. <DiscreteObjectKeyFrame KeyTime="0">
  479. <DiscreteObjectKeyFrame.Value>
  480. <Visibility>Collapsed</Visibility>
  481. </DiscreteObjectKeyFrame.Value>
  482. </DiscreteObjectKeyFrame>
  483. </ObjectAnimationUsingKeyFrames>
  484. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.0" Storyboard.TargetProperty="X" Storyboard.TargetName="R1TT">
  485. <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/>
  486. <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/>
  487. <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/>
  488. <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/>
  489. </DoubleAnimationUsingKeyFrames>
  490. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.2" Storyboard.TargetProperty="X" Storyboard.TargetName="R2TT">
  491. <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/>
  492. <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/>
  493. <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/>
  494. <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/>
  495. </DoubleAnimationUsingKeyFrames>
  496. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.4" Storyboard.TargetProperty="X" Storyboard.TargetName="R3TT">
  497. <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/>
  498. <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/>
  499. <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/>
  500. <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/>
  501. </DoubleAnimationUsingKeyFrames>
  502. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.6" Storyboard.TargetProperty="X" Storyboard.TargetName="R4TT">
  503. <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/>
  504. <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/>
  505. <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/>
  506. <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/>
  507. </DoubleAnimationUsingKeyFrames>
  508. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.8" Storyboard.TargetProperty="X" Storyboard.TargetName="R5TT">
  509. <LinearDoubleKeyFrame KeyTime="00:00:00.0" Value="0.1"/>
  510. <EasingDoubleKeyFrame KeyTime="00:00:00.5" Value="33.1" EasingFunction="{StaticResource ProgressBarEaseOut}"/>
  511. <LinearDoubleKeyFrame KeyTime="00:00:02.0" Value="66.1"/>
  512. <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="100.1" EasingFunction="{StaticResource ProgressBarEaseIn}"/>
  513. </DoubleAnimationUsingKeyFrames>
  514. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R1">
  515. <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/>
  516. <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/>
  517. </DoubleAnimationUsingKeyFrames>
  518. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.2" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R2">
  519. <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/>
  520. <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/>
  521. </DoubleAnimationUsingKeyFrames>
  522. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.4" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R3">
  523. <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/>
  524. <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/>
  525. </DoubleAnimationUsingKeyFrames>
  526. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.6" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R4">
  527. <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/>
  528. <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/>
  529. </DoubleAnimationUsingKeyFrames>
  530. <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.8" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="R5">
  531. <DiscreteDoubleKeyFrame KeyTime="0" Value="1"/>
  532. <DiscreteDoubleKeyFrame KeyTime="00:00:02.5" Value="0"/>
  533. </DoubleAnimationUsingKeyFrames>
  534. </Storyboard>
  535. </VisualState>
  536. </VisualStateGroup>
  537. </VisualStateManager.VisualStateGroups>
  538. <Grid>
  539. <Grid x:Name="DeterminateRoot" Margin="{TemplateBinding Padding}" Visibility="Visible">
  540. <Rectangle x:Name="ProgressBarTrack" Fill="{TemplateBinding Background}" Height="4" Opacity="0.1"/>
  541. <Rectangle x:Name="ProgressBarIndicator" Fill="{TemplateBinding Foreground}" HorizontalAlignment="Left" Height="4"/>
  542. </Grid>
  543. <Border x:Name="IndeterminateRoot" Margin="{TemplateBinding Padding}" Visibility="Collapsed">
  544. <Grid HorizontalAlignment="Left">
  545. <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R1" Opacity="0" CacheMode="BitmapCache">
  546. <Rectangle.RenderTransform>
  547. <TranslateTransform x:Name="R1TT"/>
  548. </Rectangle.RenderTransform>
  549. </Rectangle>
  550. <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R2" Opacity="0" CacheMode="BitmapCache">
  551. <Rectangle.RenderTransform>
  552. <TranslateTransform x:Name="R2TT"/>
  553. </Rectangle.RenderTransform>
  554. </Rectangle>
  555. <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R3" Opacity="0" CacheMode="BitmapCache">
  556. <Rectangle.RenderTransform>
  557. <TranslateTransform x:Name="R3TT"/>
  558. </Rectangle.RenderTransform>
  559. </Rectangle>
  560. <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R4" Opacity="0" CacheMode="BitmapCache">
  561. <Rectangle.RenderTransform>
  562. <TranslateTransform x:Name="R4TT"/>
  563. </Rectangle.RenderTransform>
  564. </Rectangle>
  565. <Rectangle Fill="{TemplateBinding Foreground}" Height="4" IsHitTestVisible="False" Width="4" x:Name="R5" Opacity="0" CacheMode="BitmapCache">
  566. <Rectangle.RenderTransform>
  567. <TranslateTransform x:Name="R5TT"/>
  568. </Rectangle.RenderTransform>
  569. </Rectangle>
  570. </Grid>
  571. </Border>
  572. </Grid>
  573. </unsupported:RelativeAnimatingContentControl>
  574. </ControlTemplate>
  575. </Setter.Value>
  576. </Setter>
  577. </Style>
  578. */
  579. }