ExtendedVisualStateManager.cs 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Controls.Primitives;
  6. using System.Windows.Data;
  7. using System.Windows.Media;
  8. using System.Windows.Media.Animation;
  9. using System.Windows.Media.Effects;
  10. using System.Windows.Media.Imaging;
  11. using HandyControl.Data;
  12. namespace HandyControl.Interactivity;
  13. public class ExtendedVisualStateManager : VisualStateManager
  14. {
  15. // Fields
  16. internal static readonly DependencyProperty CachedBackgroundProperty =
  17. DependencyProperty.RegisterAttached("CachedBackground", typeof(object), typeof(ExtendedVisualStateManager),
  18. new PropertyMetadata(null));
  19. internal static readonly DependencyProperty CachedEffectProperty =
  20. DependencyProperty.RegisterAttached("CachedEffect", typeof(Effect), typeof(ExtendedVisualStateManager),
  21. new PropertyMetadata(null));
  22. private static readonly List<DependencyProperty> ChildAffectingLayoutProperties;
  23. internal static readonly DependencyProperty CurrentStateProperty =
  24. DependencyProperty.RegisterAttached("CurrentState", typeof(VisualState), typeof(ExtendedVisualStateManager),
  25. new PropertyMetadata(null));
  26. internal static readonly DependencyProperty DidCacheBackgroundProperty =
  27. DependencyProperty.RegisterAttached("DidCacheBackground", typeof(bool), typeof(ExtendedVisualStateManager),
  28. new PropertyMetadata(ValueBoxes.FalseBox));
  29. private static readonly List<DependencyProperty> LayoutProperties;
  30. internal static readonly DependencyProperty LayoutStoryboardProperty =
  31. DependencyProperty.RegisterAttached("LayoutStoryboard", typeof(Storyboard),
  32. typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
  33. private static Storyboard LayoutTransitionStoryboard;
  34. private static List<FrameworkElement> MovingElements;
  35. internal static readonly DependencyProperty OriginalLayoutValuesProperty =
  36. DependencyProperty.RegisterAttached("OriginalLayoutValues", typeof(List<OriginalLayoutValueRecord>),
  37. typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
  38. public static readonly DependencyProperty RuntimeVisibilityPropertyProperty =
  39. DependencyProperty.RegisterAttached("RuntimeVisibilityProperty", typeof(DependencyProperty),
  40. typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
  41. public static readonly DependencyProperty TransitionEffectProperty =
  42. DependencyProperty.RegisterAttached("TransitionEffect", typeof(TransitionEffect),
  43. typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
  44. internal static readonly DependencyProperty TransitionEffectStoryboardProperty =
  45. DependencyProperty.RegisterAttached("TransitionEffectStoryboard", typeof(Storyboard),
  46. typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
  47. public static readonly DependencyProperty UseFluidLayoutProperty =
  48. DependencyProperty.RegisterAttached("UseFluidLayout", typeof(bool), typeof(ExtendedVisualStateManager),
  49. new PropertyMetadata(ValueBoxes.FalseBox));
  50. private bool _changingState;
  51. // Methods
  52. static ExtendedVisualStateManager()
  53. {
  54. var list = new List<DependencyProperty>
  55. {
  56. Grid.ColumnProperty,
  57. Grid.ColumnSpanProperty,
  58. Grid.RowProperty,
  59. Grid.RowSpanProperty,
  60. Canvas.LeftProperty,
  61. Canvas.TopProperty,
  62. FrameworkElement.WidthProperty,
  63. FrameworkElement.HeightProperty,
  64. FrameworkElement.MinWidthProperty,
  65. FrameworkElement.MinHeightProperty,
  66. FrameworkElement.MaxWidthProperty,
  67. FrameworkElement.MaxHeightProperty,
  68. FrameworkElement.MarginProperty,
  69. FrameworkElement.HorizontalAlignmentProperty,
  70. FrameworkElement.VerticalAlignmentProperty,
  71. UIElement.VisibilityProperty,
  72. StackPanel.OrientationProperty
  73. };
  74. LayoutProperties = list;
  75. var list2 = new List<DependencyProperty>
  76. {
  77. StackPanel.OrientationProperty
  78. };
  79. ChildAffectingLayoutProperties = list2;
  80. }
  81. // Properties
  82. public static bool IsRunningFluidLayoutTransition =>
  83. LayoutTransitionStoryboard != null;
  84. private static void AnimateTransitionEffect(FrameworkElement stateGroupsRoot, VisualTransition transition)
  85. {
  86. var element = new DoubleAnimation
  87. {
  88. Duration = transition.GeneratedDuration,
  89. EasingFunction = transition.GeneratedEasingFunction,
  90. From = 0.0,
  91. To = 1.0
  92. };
  93. var sb = new Storyboard
  94. {
  95. Duration = transition.GeneratedDuration,
  96. Children = { element }
  97. };
  98. Storyboard.SetTarget(element, stateGroupsRoot);
  99. Storyboard.SetTargetProperty(element,
  100. new PropertyPath("(0).(1)", UIElement.EffectProperty, TransitionEffect.ProgressProperty));
  101. if (stateGroupsRoot is Panel panel && panel.Background == null)
  102. {
  103. SetDidCacheBackground(panel, true);
  104. TransferLocalValue(panel, Panel.BackgroundProperty, CachedBackgroundProperty);
  105. panel.Background = Brushes.Transparent;
  106. }
  107. sb.Completed += delegate
  108. {
  109. if (Equals(GetTransitionEffectStoryboard(stateGroupsRoot), sb))
  110. FinishTransitionEffectAnimation(stateGroupsRoot);
  111. };
  112. SetTransitionEffectStoryboard(stateGroupsRoot, sb);
  113. sb.Begin();
  114. }
  115. private static object CacheLocalValueHelper(DependencyObject dependencyObject, DependencyProperty property)
  116. {
  117. return dependencyObject.ReadLocalValue(property);
  118. }
  119. private static void control_LayoutUpdated(object sender, EventArgs e)
  120. {
  121. if (LayoutTransitionStoryboard != null)
  122. foreach (var element in MovingElements)
  123. {
  124. if (element.Parent is WrapperCanvas parent)
  125. {
  126. var layoutRect = GetLayoutRect(parent);
  127. var newRect = parent.NewRect;
  128. var renderTransform = parent.RenderTransform as TranslateTransform;
  129. var num = renderTransform?.X ?? 0.0;
  130. var num2 = renderTransform?.Y ?? 0.0;
  131. var num3 = newRect.Left - layoutRect.Left;
  132. var num4 = newRect.Top - layoutRect.Top;
  133. if (Math.Abs(num - num3) > 0.001 || Math.Abs(num2 - num4) > 0.001)
  134. {
  135. if (renderTransform == null)
  136. {
  137. renderTransform = new TranslateTransform();
  138. parent.RenderTransform = renderTransform;
  139. }
  140. renderTransform.X = num3;
  141. renderTransform.Y = num4;
  142. }
  143. }
  144. }
  145. }
  146. private static void CopyLayoutProperties(FrameworkElement source, FrameworkElement target, bool restoring)
  147. {
  148. var canvas = restoring ? (WrapperCanvas) source : (WrapperCanvas) target;
  149. if (canvas.LocalValueCache == null)
  150. canvas.LocalValueCache = new Dictionary<DependencyProperty, object>();
  151. foreach (var property in LayoutProperties)
  152. if (!ChildAffectingLayoutProperties.Contains(property))
  153. if (restoring)
  154. {
  155. ReplaceCachedLocalValueHelper(target, property, canvas.LocalValueCache[property]);
  156. }
  157. else
  158. {
  159. var obj2 = target.GetValue(property);
  160. var obj3 = CacheLocalValueHelper(source, property);
  161. canvas.LocalValueCache[property] = obj3;
  162. if (IsVisibilityProperty(property))
  163. canvas.DestinationVisibilityCache = (Visibility) source.GetValue(property);
  164. else
  165. target.SetValue(property, source.GetValue(property));
  166. source.SetValue(property, obj2);
  167. }
  168. }
  169. private static Storyboard CreateLayoutTransitionStoryboard(VisualTransition transition,
  170. List<FrameworkElement> movingElements, Dictionary<FrameworkElement, double> oldOpacities)
  171. {
  172. var duration = transition?.GeneratedDuration ?? new Duration(TimeSpan.Zero);
  173. var generatedEasingFunction = transition?.GeneratedEasingFunction;
  174. var storyboard = new Storyboard
  175. {
  176. Duration = duration
  177. };
  178. foreach (var element in movingElements)
  179. {
  180. if (element.Parent is WrapperCanvas parent)
  181. {
  182. var animation = new DoubleAnimation
  183. {
  184. From = 1.0,
  185. To = 0.0,
  186. Duration = duration,
  187. EasingFunction = generatedEasingFunction
  188. };
  189. Storyboard.SetTarget(animation, parent);
  190. Storyboard.SetTargetProperty(animation, new PropertyPath(WrapperCanvas.SimulationProgressProperty));
  191. storyboard.Children.Add(animation);
  192. parent.SimulationProgress = 1.0;
  193. var newRect = parent.NewRect;
  194. if (!IsClose(parent.Width, newRect.Width))
  195. {
  196. var animation3 = new DoubleAnimation
  197. {
  198. From = newRect.Width,
  199. To = newRect.Width,
  200. Duration = duration
  201. };
  202. Storyboard.SetTarget(animation3, parent);
  203. Storyboard.SetTargetProperty(animation3, new PropertyPath(FrameworkElement.WidthProperty));
  204. storyboard.Children.Add(animation3);
  205. }
  206. if (!IsClose(parent.Height, newRect.Height))
  207. {
  208. var animation5 = new DoubleAnimation
  209. {
  210. From = newRect.Height,
  211. To = newRect.Height,
  212. Duration = duration
  213. };
  214. Storyboard.SetTarget(animation5, parent);
  215. Storyboard.SetTargetProperty(animation5, new PropertyPath(FrameworkElement.HeightProperty));
  216. storyboard.Children.Add(animation5);
  217. }
  218. if (parent.DestinationVisibilityCache == Visibility.Collapsed)
  219. {
  220. var margin = parent.Margin;
  221. if (!IsClose(margin.Left, 0.0) || !IsClose(margin.Top, 0.0) || !IsClose(margin.Right, 0.0) ||
  222. !IsClose(margin.Bottom, 0.0))
  223. {
  224. var frames = new ObjectAnimationUsingKeyFrames
  225. {
  226. Duration = duration
  227. };
  228. var frame2 = new DiscreteObjectKeyFrame
  229. {
  230. KeyTime = TimeSpan.Zero
  231. };
  232. var thickness2 = new Thickness();
  233. frame2.Value = thickness2;
  234. var keyFrame = frame2;
  235. frames.KeyFrames.Add(keyFrame);
  236. Storyboard.SetTarget(frames, parent);
  237. Storyboard.SetTargetProperty(frames, new PropertyPath(FrameworkElement.MarginProperty));
  238. storyboard.Children.Add(frames);
  239. }
  240. if (!IsClose(parent.MinWidth, 0.0))
  241. {
  242. var animation7 = new DoubleAnimation
  243. {
  244. From = 0.0,
  245. To = 0.0,
  246. Duration = duration
  247. };
  248. Storyboard.SetTarget(animation7, parent);
  249. Storyboard.SetTargetProperty(animation7,
  250. new PropertyPath(FrameworkElement.MinWidthProperty));
  251. storyboard.Children.Add(animation7);
  252. }
  253. if (!IsClose(parent.MinHeight, 0.0))
  254. {
  255. var animation9 = new DoubleAnimation
  256. {
  257. From = 0.0,
  258. To = 0.0,
  259. Duration = duration
  260. };
  261. Storyboard.SetTarget(animation9, parent);
  262. Storyboard.SetTargetProperty(animation9,
  263. new PropertyPath(FrameworkElement.MinHeightProperty));
  264. storyboard.Children.Add(animation9);
  265. }
  266. }
  267. }
  268. }
  269. foreach (var element2 in oldOpacities.Keys)
  270. {
  271. if (element2.Parent is WrapperCanvas canvas2)
  272. {
  273. var a = oldOpacities[element2];
  274. var num2 = canvas2.DestinationVisibilityCache == Visibility.Visible ? 1.0 : 0.0;
  275. if (!IsClose(a, 1.0) || !IsClose(num2, 1.0))
  276. {
  277. var animation11 = new DoubleAnimation
  278. {
  279. From = a,
  280. To = num2,
  281. Duration = duration,
  282. EasingFunction = generatedEasingFunction
  283. };
  284. Storyboard.SetTarget(animation11, canvas2);
  285. Storyboard.SetTargetProperty(animation11, new PropertyPath(UIElement.OpacityProperty));
  286. storyboard.Children.Add(animation11);
  287. }
  288. }
  289. }
  290. return storyboard;
  291. }
  292. private static Storyboard ExtractLayoutStoryboard(VisualState state)
  293. {
  294. Storyboard layoutStoryboard = null;
  295. if (state.Storyboard != null)
  296. {
  297. layoutStoryboard = GetLayoutStoryboard(state.Storyboard);
  298. if (layoutStoryboard == null)
  299. {
  300. layoutStoryboard = new Storyboard();
  301. for (var i = state.Storyboard.Children.Count - 1; i >= 0; i--)
  302. {
  303. var timeline = state.Storyboard.Children[i];
  304. if (LayoutPropertyFromTimeline(timeline, false) != null)
  305. {
  306. state.Storyboard.Children.RemoveAt(i);
  307. layoutStoryboard.Children.Add(timeline);
  308. }
  309. }
  310. SetLayoutStoryboard(state.Storyboard, layoutStoryboard);
  311. }
  312. }
  313. if (layoutStoryboard == null)
  314. return new Storyboard();
  315. return layoutStoryboard;
  316. }
  317. private static List<FrameworkElement> FindTargetElements(FrameworkElement control,
  318. FrameworkElement templateRoot, Storyboard layoutStoryboard,
  319. List<OriginalLayoutValueRecord> originalValueRecords, List<FrameworkElement> movingElements)
  320. {
  321. var list = new List<FrameworkElement>();
  322. if (movingElements != null)
  323. list.AddRange(movingElements);
  324. foreach (var timeline in layoutStoryboard.Children)
  325. {
  326. var item = (FrameworkElement) GetTimelineTarget(control, templateRoot, timeline);
  327. if (item != null)
  328. {
  329. if (!list.Contains(item))
  330. list.Add(item);
  331. if (ChildAffectingLayoutProperties.Contains(LayoutPropertyFromTimeline(timeline, false)))
  332. {
  333. if (item is Panel panel)
  334. foreach (FrameworkElement element2 in panel.Children)
  335. if (!list.Contains(element2) && !(element2 is WrapperCanvas))
  336. list.Add(element2);
  337. }
  338. }
  339. }
  340. foreach (var record in originalValueRecords)
  341. {
  342. if (!list.Contains(record.Element))
  343. list.Add(record.Element);
  344. if (ChildAffectingLayoutProperties.Contains(record.Property))
  345. {
  346. if (record.Element is Panel element)
  347. foreach (FrameworkElement element3 in element.Children)
  348. if (!list.Contains(element3) && !(element3 is WrapperCanvas))
  349. list.Add(element3);
  350. }
  351. }
  352. for (var i = 0; i < list.Count; i++)
  353. {
  354. var reference = list[i];
  355. var parent = VisualTreeHelper.GetParent(reference) as FrameworkElement;
  356. if (movingElements != null && movingElements.Contains(reference) && parent is WrapperCanvas)
  357. parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
  358. if (parent != null)
  359. {
  360. if (!list.Contains(parent))
  361. list.Add(parent);
  362. for (var j = 0; j < VisualTreeHelper.GetChildrenCount(parent); j++)
  363. {
  364. if (VisualTreeHelper.GetChild(parent, j) is FrameworkElement child && !list.Contains(child) && !(child is WrapperCanvas))
  365. list.Add(child);
  366. }
  367. }
  368. }
  369. return list;
  370. }
  371. private static VisualTransition FindTransition(VisualStateGroup group, VisualState previousState,
  372. VisualState state)
  373. {
  374. var str = previousState != null ? previousState.Name : string.Empty;
  375. var str2 = state != null ? state.Name : string.Empty;
  376. var num = -1;
  377. VisualTransition transition = null;
  378. foreach (VisualTransition transition2 in group.Transitions)
  379. {
  380. var num2 = 0;
  381. if (transition2.From == str)
  382. num2++;
  383. else if (!string.IsNullOrEmpty(transition2.From))
  384. continue;
  385. if (transition2.To == str2)
  386. num2 += 2;
  387. else if (!string.IsNullOrEmpty(transition2.To))
  388. continue;
  389. if (num2 > num)
  390. {
  391. num = num2;
  392. transition = transition2;
  393. }
  394. }
  395. return transition;
  396. }
  397. private static bool FinishesWithZeroOpacity(FrameworkElement control, FrameworkElement stateGroupsRoot,
  398. VisualState state, VisualState previousState)
  399. {
  400. if (state.Storyboard != null)
  401. foreach (var timeline in state.Storyboard.Children)
  402. if (TimelineIsAnimatingRootOpacity(timeline, control, stateGroupsRoot))
  403. {
  404. var valueFromTimeline = GetValueFromTimeline(timeline, out var flag);
  405. return flag && valueFromTimeline is double d && Math.Abs(d) < 0.001;
  406. }
  407. if (previousState?.Storyboard == null)
  408. return Math.Abs(stateGroupsRoot.Opacity) < 0.001;
  409. foreach (var timeline2 in previousState.Storyboard.Children)
  410. TimelineIsAnimatingRootOpacity(timeline2, control, stateGroupsRoot);
  411. var animationBaseValue = (double) stateGroupsRoot.GetAnimationBaseValue(UIElement.OpacityProperty);
  412. return Math.Abs(animationBaseValue) < 0.001;
  413. }
  414. private static void FinishTransitionEffectAnimation(FrameworkElement stateGroupsRoot)
  415. {
  416. SetTransitionEffectStoryboard(stateGroupsRoot, null);
  417. TransferLocalValue(stateGroupsRoot, CachedEffectProperty, UIElement.EffectProperty);
  418. if (GetDidCacheBackground(stateGroupsRoot))
  419. {
  420. TransferLocalValue(stateGroupsRoot, CachedBackgroundProperty, Panel.BackgroundProperty);
  421. SetDidCacheBackground(stateGroupsRoot, false);
  422. }
  423. }
  424. internal static object GetCachedBackground(DependencyObject obj)
  425. {
  426. return obj.GetValue(CachedBackgroundProperty);
  427. }
  428. internal static Effect GetCachedEffect(DependencyObject obj)
  429. {
  430. return (Effect) obj.GetValue(CachedEffectProperty);
  431. }
  432. internal static VisualState GetCurrentState(DependencyObject obj)
  433. {
  434. return (VisualState) obj.GetValue(CurrentStateProperty);
  435. }
  436. internal static bool GetDidCacheBackground(DependencyObject obj)
  437. {
  438. return (bool) obj.GetValue(DidCacheBackgroundProperty);
  439. }
  440. internal static Rect GetLayoutRect(FrameworkElement element)
  441. {
  442. var actualWidth = element.ActualWidth;
  443. var actualHeight = element.ActualHeight;
  444. if (element is Image || element is MediaElement)
  445. if (element.Parent is Canvas)
  446. {
  447. actualWidth = double.IsNaN(element.Width) ? actualWidth : element.Width;
  448. actualHeight = double.IsNaN(element.Height) ? actualHeight : element.Height;
  449. }
  450. else
  451. {
  452. actualWidth = element.RenderSize.Width;
  453. actualHeight = element.RenderSize.Height;
  454. }
  455. actualWidth = element.Visibility == Visibility.Collapsed ? 0.0 : actualWidth;
  456. actualHeight = element.Visibility == Visibility.Collapsed ? 0.0 : actualHeight;
  457. var margin = element.Margin;
  458. var layoutSlot = LayoutInformation.GetLayoutSlot(element);
  459. var x = 0.0;
  460. var y = 0.0;
  461. x = element.HorizontalAlignment switch
  462. {
  463. HorizontalAlignment.Left => layoutSlot.Left + margin.Left,
  464. HorizontalAlignment.Center => (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 -
  465. actualWidth / 2.0,
  466. HorizontalAlignment.Right => layoutSlot.Right - margin.Right - actualWidth,
  467. HorizontalAlignment.Stretch => Math.Max(layoutSlot.Left + margin.Left,
  468. (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - actualWidth / 2.0),
  469. _ => x
  470. };
  471. y = element.VerticalAlignment switch
  472. {
  473. VerticalAlignment.Top => layoutSlot.Top + margin.Top,
  474. VerticalAlignment.Center => (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 -
  475. actualHeight / 2.0,
  476. VerticalAlignment.Bottom => layoutSlot.Bottom - margin.Bottom - actualHeight,
  477. VerticalAlignment.Stretch => Math.Max(layoutSlot.Top + margin.Top,
  478. (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - actualHeight / 2.0),
  479. _ => y
  480. };
  481. return new Rect(x, y, actualWidth, actualHeight);
  482. }
  483. internal static Storyboard GetLayoutStoryboard(DependencyObject obj)
  484. {
  485. return (Storyboard) obj.GetValue(LayoutStoryboardProperty);
  486. }
  487. private static Dictionary<FrameworkElement, double> GetOldOpacities(FrameworkElement control,
  488. FrameworkElement templateRoot, Storyboard layoutStoryboard,
  489. List<OriginalLayoutValueRecord> originalValueRecords, List<FrameworkElement> movingElements)
  490. {
  491. var dictionary = new Dictionary<FrameworkElement, double>();
  492. if (movingElements != null)
  493. foreach (var element in movingElements)
  494. {
  495. if (element.Parent is WrapperCanvas parent)
  496. dictionary.Add(element, parent.Opacity);
  497. }
  498. for (var i = originalValueRecords.Count - 1; i >= 0; i--)
  499. {
  500. var record = originalValueRecords[i];
  501. if (IsVisibilityProperty(record.Property) && !dictionary.TryGetValue(record.Element, out var num2))
  502. {
  503. num2 = (Visibility) record.Element.GetValue(record.Property) == Visibility.Visible ? 1.0 : 0.0;
  504. dictionary.Add(record.Element, num2);
  505. }
  506. }
  507. foreach (var timeline in layoutStoryboard.Children)
  508. {
  509. var key = (FrameworkElement) GetTimelineTarget(control, templateRoot, timeline);
  510. var property = LayoutPropertyFromTimeline(timeline, true);
  511. if (key != null && IsVisibilityProperty(property) && !dictionary.TryGetValue(key, out var num3))
  512. {
  513. num3 = (Visibility) key.GetValue(property) == Visibility.Visible ? 1.0 : 0.0;
  514. dictionary.Add(key, num3);
  515. }
  516. }
  517. return dictionary;
  518. }
  519. internal static List<OriginalLayoutValueRecord> GetOriginalLayoutValues(DependencyObject obj)
  520. {
  521. return (List<OriginalLayoutValueRecord>) obj.GetValue(OriginalLayoutValuesProperty);
  522. }
  523. private static Dictionary<FrameworkElement, Rect> GetRectsOfTargets(IEnumerable<FrameworkElement> targets,
  524. ICollection<FrameworkElement> movingElements)
  525. {
  526. var dictionary = new Dictionary<FrameworkElement, Rect>();
  527. foreach (var element in targets)
  528. {
  529. Rect layoutRect;
  530. if (movingElements != null && movingElements.Contains(element) && element.Parent is WrapperCanvas parent)
  531. {
  532. layoutRect = GetLayoutRect(parent);
  533. var renderTransform = parent.RenderTransform as TranslateTransform;
  534. var left = Canvas.GetLeft(element);
  535. var top = Canvas.GetTop(element);
  536. layoutRect = new Rect(
  537. layoutRect.Left + (double.IsNaN(left) ? 0.0 : left) +
  538. (renderTransform?.X ?? 0.0),
  539. layoutRect.Top + (double.IsNaN(top) ? 0.0 : top) +
  540. (renderTransform?.Y ?? 0.0), element.ActualWidth, element.ActualHeight);
  541. }
  542. else
  543. {
  544. layoutRect = GetLayoutRect(element);
  545. }
  546. dictionary.Add(element, layoutRect);
  547. }
  548. return dictionary;
  549. }
  550. public static DependencyProperty GetRuntimeVisibilityProperty(DependencyObject obj)
  551. {
  552. return (DependencyProperty) obj.GetValue(RuntimeVisibilityPropertyProperty);
  553. }
  554. private static object GetTimelineTarget(FrameworkElement control, FrameworkElement templateRoot,
  555. Timeline timeline)
  556. {
  557. var targetName = Storyboard.GetTargetName(timeline);
  558. if (string.IsNullOrEmpty(targetName))
  559. return null;
  560. if (control is UserControl)
  561. return control.FindName(targetName);
  562. return templateRoot.FindName(targetName);
  563. }
  564. public static TransitionEffect GetTransitionEffect(DependencyObject obj)
  565. {
  566. return (TransitionEffect) obj.GetValue(TransitionEffectProperty);
  567. }
  568. internal static Storyboard GetTransitionEffectStoryboard(DependencyObject obj)
  569. {
  570. return (Storyboard) obj.GetValue(TransitionEffectStoryboardProperty);
  571. }
  572. public static bool GetUseFluidLayout(DependencyObject obj)
  573. {
  574. return (bool) obj.GetValue(UseFluidLayoutProperty);
  575. }
  576. private static object GetValueFromTimeline(Timeline timeline, out bool gotValue)
  577. {
  578. if (timeline is ObjectAnimationUsingKeyFrames frames)
  579. {
  580. gotValue = true;
  581. return frames.KeyFrames[0].Value;
  582. }
  583. if (timeline is DoubleAnimationUsingKeyFrames frames2)
  584. {
  585. gotValue = true;
  586. return frames2.KeyFrames[0].Value;
  587. }
  588. if (timeline is DoubleAnimation animation)
  589. {
  590. gotValue = true;
  591. return animation.To;
  592. }
  593. if (timeline is ThicknessAnimationUsingKeyFrames frames3)
  594. {
  595. gotValue = true;
  596. return frames3.KeyFrames[0].Value;
  597. }
  598. if (timeline is ThicknessAnimation animation2)
  599. {
  600. gotValue = true;
  601. return animation2.To;
  602. }
  603. if (timeline is Int32AnimationUsingKeyFrames frames4)
  604. {
  605. gotValue = true;
  606. return frames4.KeyFrames[0].Value;
  607. }
  608. if (timeline is Int32Animation animation3)
  609. {
  610. gotValue = true;
  611. return animation3.To;
  612. }
  613. gotValue = false;
  614. return null;
  615. }
  616. protected override bool GoToStateCore(FrameworkElement control, FrameworkElement stateGroupsRoot,
  617. string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
  618. {
  619. if (_changingState)
  620. return false;
  621. var currentState = GetCurrentState(group);
  622. if (!Equals(currentState, state))
  623. {
  624. var transition = FindTransition(group, currentState, state);
  625. var animateWithTransitionEffect =
  626. PrepareTransitionEffectImage(stateGroupsRoot, useTransitions, transition);
  627. if (!GetUseFluidLayout(group))
  628. return TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
  629. useTransitions, transition, animateWithTransitionEffect, currentState);
  630. var layoutStoryboard = ExtractLayoutStoryboard(state);
  631. var originalLayoutValues = GetOriginalLayoutValues(group);
  632. if (originalLayoutValues == null)
  633. {
  634. originalLayoutValues = new List<OriginalLayoutValueRecord>();
  635. SetOriginalLayoutValues(group, originalLayoutValues);
  636. }
  637. if (!useTransitions)
  638. {
  639. if (LayoutTransitionStoryboard != null)
  640. StopAnimations();
  641. var flag2 = TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
  642. false, transition, animateWithTransitionEffect, currentState);
  643. SetLayoutStoryboardProperties(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues);
  644. return flag2;
  645. }
  646. if (layoutStoryboard.Children.Count == 0 && originalLayoutValues.Count == 0)
  647. return TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
  648. true, transition, animateWithTransitionEffect, currentState);
  649. try
  650. {
  651. _changingState = true;
  652. stateGroupsRoot.UpdateLayout();
  653. var targets = FindTargetElements(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues,
  654. MovingElements);
  655. var rectsOfTargets = GetRectsOfTargets(targets, MovingElements);
  656. var oldOpacities = GetOldOpacities(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues,
  657. MovingElements);
  658. if (LayoutTransitionStoryboard != null)
  659. {
  660. stateGroupsRoot.LayoutUpdated -= control_LayoutUpdated;
  661. StopAnimations();
  662. stateGroupsRoot.UpdateLayout();
  663. }
  664. TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
  665. true, transition, animateWithTransitionEffect, currentState);
  666. SetLayoutStoryboardProperties(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues);
  667. stateGroupsRoot.UpdateLayout();
  668. var newRects = GetRectsOfTargets(targets, null);
  669. MovingElements = new List<FrameworkElement>();
  670. foreach (var element in targets)
  671. if (rectsOfTargets[element] != newRects[element])
  672. MovingElements.Add(element);
  673. foreach (var element2 in oldOpacities.Keys)
  674. if (!MovingElements.Contains(element2))
  675. MovingElements.Add(element2);
  676. WrapMovingElementsInCanvases(MovingElements, rectsOfTargets, newRects);
  677. stateGroupsRoot.LayoutUpdated += control_LayoutUpdated;
  678. LayoutTransitionStoryboard =
  679. CreateLayoutTransitionStoryboard(transition, MovingElements, oldOpacities);
  680. void Handler(object sender, EventArgs e)
  681. {
  682. stateGroupsRoot.LayoutUpdated -= control_LayoutUpdated;
  683. StopAnimations();
  684. }
  685. LayoutTransitionStoryboard.Completed += Handler;
  686. LayoutTransitionStoryboard.Begin();
  687. }
  688. finally
  689. {
  690. _changingState = false;
  691. }
  692. }
  693. return true;
  694. }
  695. private static bool IsClose(double a, double b)
  696. {
  697. return Math.Abs(a - b) < 1E-07;
  698. }
  699. private static bool IsVisibilityProperty(DependencyProperty property)
  700. {
  701. if (property != UIElement.VisibilityProperty)
  702. return property.Name == "RuntimeVisibility";
  703. return true;
  704. }
  705. private static DependencyProperty LayoutPropertyFromTimeline(Timeline timeline, bool forceRuntimeProperty)
  706. {
  707. var targetProperty = Storyboard.GetTargetProperty(timeline);
  708. if (targetProperty != null &&
  709. targetProperty.PathParameters.Count != 0)
  710. {
  711. if (targetProperty.PathParameters[0] is DependencyProperty item)
  712. {
  713. if (item.Name == "RuntimeVisibility" &&
  714. item.OwnerType.Name.EndsWith("DesignTimeProperties", StringComparison.Ordinal))
  715. {
  716. if (!LayoutProperties.Contains(item))
  717. LayoutProperties.Add(item);
  718. if (!forceRuntimeProperty)
  719. return UIElement.VisibilityProperty;
  720. return item;
  721. }
  722. if (item.Name == "RuntimeWidth" &&
  723. item.OwnerType.Name.EndsWith("DesignTimeProperties", StringComparison.Ordinal))
  724. {
  725. if (!LayoutProperties.Contains(item))
  726. LayoutProperties.Add(item);
  727. if (!forceRuntimeProperty)
  728. return FrameworkElement.WidthProperty;
  729. return item;
  730. }
  731. if (item.Name == "RuntimeHeight" &&
  732. item.OwnerType.Name.EndsWith("DesignTimeProperties", StringComparison.Ordinal))
  733. {
  734. if (!LayoutProperties.Contains(item))
  735. LayoutProperties.Add(item);
  736. if (!forceRuntimeProperty)
  737. return FrameworkElement.HeightProperty;
  738. return item;
  739. }
  740. if (LayoutProperties.Contains(item))
  741. return item;
  742. }
  743. }
  744. return null;
  745. }
  746. private static bool PrepareTransitionEffectImage(FrameworkElement stateGroupsRoot, bool useTransitions,
  747. VisualTransition transition)
  748. {
  749. var effect = transition == null ? null : GetTransitionEffect(transition);
  750. var flag = false;
  751. if (effect != null)
  752. {
  753. effect = effect.CloneCurrentValue();
  754. if (useTransitions)
  755. {
  756. flag = true;
  757. var pixelWidth = (int) Math.Max(1.0, stateGroupsRoot.ActualWidth);
  758. var pixelHeight = (int) Math.Max(1.0, stateGroupsRoot.ActualHeight);
  759. var bitmap = new RenderTargetBitmap(pixelWidth, pixelHeight, 96.0, 96.0, PixelFormats.Pbgra32);
  760. bitmap.Render(stateGroupsRoot);
  761. var brush = new ImageBrush
  762. {
  763. ImageSource = bitmap
  764. };
  765. effect.OldImage = brush;
  766. }
  767. var transitionEffectStoryboard = GetTransitionEffectStoryboard(stateGroupsRoot);
  768. if (transitionEffectStoryboard != null)
  769. {
  770. transitionEffectStoryboard.Stop();
  771. FinishTransitionEffectAnimation(stateGroupsRoot);
  772. }
  773. if (useTransitions)
  774. {
  775. TransferLocalValue(stateGroupsRoot, UIElement.EffectProperty, CachedEffectProperty);
  776. stateGroupsRoot.Effect = effect;
  777. }
  778. }
  779. return flag;
  780. }
  781. private static void ReplaceCachedLocalValueHelper(FrameworkElement element, DependencyProperty property,
  782. object value)
  783. {
  784. if (value == DependencyProperty.UnsetValue)
  785. {
  786. element.ClearValue(property);
  787. }
  788. else
  789. {
  790. if (value is BindingExpressionBase base2)
  791. element.SetBinding(property, base2.ParentBindingBase);
  792. else
  793. element.SetValue(property, value);
  794. }
  795. }
  796. internal static void SetCachedBackground(DependencyObject obj, object value)
  797. {
  798. obj.SetValue(CachedBackgroundProperty, value);
  799. }
  800. internal static void SetCachedEffect(DependencyObject obj, Effect value)
  801. {
  802. obj.SetValue(CachedEffectProperty, value);
  803. }
  804. internal static void SetCurrentState(DependencyObject obj, VisualState value)
  805. {
  806. obj.SetValue(CurrentStateProperty, value);
  807. }
  808. internal static void SetDidCacheBackground(DependencyObject obj, bool value)
  809. {
  810. obj.SetValue(DidCacheBackgroundProperty, ValueBoxes.BooleanBox(value));
  811. }
  812. internal static void SetLayoutStoryboard(DependencyObject obj, Storyboard value)
  813. {
  814. obj.SetValue(LayoutStoryboardProperty, value);
  815. }
  816. private static void SetLayoutStoryboardProperties(FrameworkElement control, FrameworkElement templateRoot,
  817. Storyboard layoutStoryboard, List<OriginalLayoutValueRecord> originalValueRecords)
  818. {
  819. foreach (var record in originalValueRecords)
  820. ReplaceCachedLocalValueHelper(record.Element, record.Property, record.Value);
  821. originalValueRecords.Clear();
  822. foreach (var timeline in layoutStoryboard.Children)
  823. {
  824. var dependencyObject = (FrameworkElement) GetTimelineTarget(control, templateRoot, timeline);
  825. var property = LayoutPropertyFromTimeline(timeline, true);
  826. if (dependencyObject != null && property != null)
  827. {
  828. var valueFromTimeline = GetValueFromTimeline(timeline, out var flag);
  829. if (flag)
  830. {
  831. var item = new OriginalLayoutValueRecord
  832. {
  833. Element = dependencyObject,
  834. Property = property,
  835. Value = CacheLocalValueHelper(dependencyObject, property)
  836. };
  837. originalValueRecords.Add(item);
  838. dependencyObject.SetValue(property, valueFromTimeline);
  839. }
  840. }
  841. }
  842. }
  843. internal static void SetOriginalLayoutValues(DependencyObject obj, List<OriginalLayoutValueRecord> value)
  844. {
  845. obj.SetValue(OriginalLayoutValuesProperty, value);
  846. }
  847. public static void SetRuntimeVisibilityProperty(DependencyObject obj, DependencyProperty value)
  848. {
  849. obj.SetValue(RuntimeVisibilityPropertyProperty, value);
  850. }
  851. public static void SetTransitionEffect(DependencyObject obj, TransitionEffect value)
  852. {
  853. obj.SetValue(TransitionEffectProperty, value);
  854. }
  855. internal static void SetTransitionEffectStoryboard(DependencyObject obj, Storyboard value)
  856. {
  857. obj.SetValue(TransitionEffectStoryboardProperty, value);
  858. }
  859. public static void SetUseFluidLayout(DependencyObject obj, bool value)
  860. {
  861. obj.SetValue(UseFluidLayoutProperty, ValueBoxes.BooleanBox(value));
  862. }
  863. private static void StopAnimations()
  864. {
  865. if (LayoutTransitionStoryboard != null)
  866. {
  867. LayoutTransitionStoryboard.Stop();
  868. LayoutTransitionStoryboard = null;
  869. }
  870. if (MovingElements != null)
  871. {
  872. UnwrapMovingElementsFromCanvases(MovingElements);
  873. MovingElements = null;
  874. }
  875. }
  876. private static bool TimelineIsAnimatingRootOpacity(Timeline timeline, FrameworkElement control,
  877. FrameworkElement stateGroupsRoot)
  878. {
  879. if (!Equals(GetTimelineTarget(control, stateGroupsRoot, timeline), stateGroupsRoot))
  880. return false;
  881. var targetProperty = Storyboard.GetTargetProperty(timeline);
  882. return targetProperty != null &&
  883. targetProperty.PathParameters.Count != 0 &&
  884. targetProperty.PathParameters[0] == UIElement.OpacityProperty;
  885. }
  886. private static void TransferLocalValue(FrameworkElement element, DependencyProperty sourceProperty,
  887. DependencyProperty destProperty)
  888. {
  889. var obj2 = CacheLocalValueHelper(element, sourceProperty);
  890. ReplaceCachedLocalValueHelper(element, destProperty, obj2);
  891. }
  892. private bool TransitionEffectAwareGoToStateCore(FrameworkElement control, FrameworkElement stateGroupsRoot,
  893. string stateName, VisualStateGroup group, VisualState state, bool useTransitions,
  894. VisualTransition transition, bool animateWithTransitionEffect, VisualState previousState)
  895. {
  896. IEasingFunction generatedEasingFunction = null;
  897. if (animateWithTransitionEffect)
  898. {
  899. generatedEasingFunction = transition.GeneratedEasingFunction;
  900. var function2 = new DummyEasingFunction
  901. {
  902. DummyValue = FinishesWithZeroOpacity(control, stateGroupsRoot, state, previousState) ? 0.01 : 0.0
  903. };
  904. transition.GeneratedEasingFunction = function2;
  905. }
  906. var flag = base.GoToStateCore(control, stateGroupsRoot, stateName, group, state, useTransitions);
  907. if (animateWithTransitionEffect)
  908. {
  909. transition.GeneratedEasingFunction = generatedEasingFunction;
  910. if (flag)
  911. AnimateTransitionEffect(stateGroupsRoot, transition);
  912. }
  913. SetCurrentState(group, state);
  914. return flag;
  915. }
  916. private static void UnwrapMovingElementsFromCanvases(List<FrameworkElement> movingElements)
  917. {
  918. foreach (var element in movingElements)
  919. {
  920. if (element.Parent is WrapperCanvas parent)
  921. {
  922. var obj2 = CacheLocalValueHelper(element, FrameworkElement.DataContextProperty);
  923. element.DataContext = element.DataContext;
  924. var element2 = VisualTreeHelper.GetParent(parent) as FrameworkElement;
  925. parent.Children.Remove(element);
  926. if (element2 is Panel panel)
  927. {
  928. var index = panel.Children.IndexOf(parent);
  929. panel.Children.RemoveAt(index);
  930. panel.Children.Insert(index, element);
  931. }
  932. else
  933. {
  934. if (element2 is Decorator decorator)
  935. decorator.Child = element;
  936. }
  937. CopyLayoutProperties(parent, element, true);
  938. ReplaceCachedLocalValueHelper(element, FrameworkElement.DataContextProperty, obj2);
  939. }
  940. }
  941. }
  942. private static void WrapMovingElementsInCanvases(List<FrameworkElement> movingElements,
  943. Dictionary<FrameworkElement, Rect> oldRects, Dictionary<FrameworkElement, Rect> newRects)
  944. {
  945. foreach (var element in movingElements)
  946. {
  947. var parent = VisualTreeHelper.GetParent(element) as FrameworkElement;
  948. var canvas = new WrapperCanvas
  949. {
  950. OldRect = oldRects[element],
  951. NewRect = newRects[element]
  952. };
  953. var obj2 = CacheLocalValueHelper(element, FrameworkElement.DataContextProperty);
  954. element.DataContext = element.DataContext;
  955. var flag = true;
  956. if (parent is Panel panel && !panel.IsItemsHost)
  957. {
  958. var index = panel.Children.IndexOf(element);
  959. panel.Children.RemoveAt(index);
  960. panel.Children.Insert(index, canvas);
  961. }
  962. else
  963. {
  964. if (parent is Decorator decorator)
  965. decorator.Child = canvas;
  966. else
  967. flag = false;
  968. }
  969. if (flag)
  970. {
  971. canvas.Children.Add(element);
  972. CopyLayoutProperties(element, canvas, false);
  973. ReplaceCachedLocalValueHelper(element, FrameworkElement.DataContextProperty, obj2);
  974. }
  975. }
  976. }
  977. // Nested Types
  978. private class DummyEasingFunction : EasingFunctionBase
  979. {
  980. // Fields
  981. public static readonly DependencyProperty DummyValueProperty = DependencyProperty.Register("DummyValue",
  982. typeof(double), typeof(DummyEasingFunction), new PropertyMetadata(0.0));
  983. // Properties
  984. public double DummyValue
  985. {
  986. private get => (double) GetValue(DummyValueProperty);
  987. set => SetValue(DummyValueProperty, value);
  988. }
  989. // Methods
  990. protected override Freezable CreateInstanceCore()
  991. {
  992. return new DummyEasingFunction();
  993. }
  994. protected override double EaseInCore(double normalizedTime)
  995. {
  996. return DummyValue;
  997. }
  998. }
  999. internal class OriginalLayoutValueRecord
  1000. {
  1001. // Properties
  1002. public FrameworkElement Element { get; set; }
  1003. public DependencyProperty Property { get; set; }
  1004. public object Value { get; set; }
  1005. }
  1006. internal class WrapperCanvas : Canvas
  1007. {
  1008. // Fields
  1009. internal static readonly DependencyProperty SimulationProgressProperty =
  1010. DependencyProperty.Register("SimulationProgress", typeof(double), typeof(WrapperCanvas),
  1011. new PropertyMetadata(0.0, SimulationProgressChanged));
  1012. // Properties
  1013. public Visibility DestinationVisibilityCache { get; set; }
  1014. public Dictionary<DependencyProperty, object> LocalValueCache { get; set; }
  1015. public Rect NewRect { get; set; }
  1016. public Rect OldRect { get; set; }
  1017. public double SimulationProgress
  1018. {
  1019. get =>
  1020. (double) GetValue(SimulationProgressProperty);
  1021. set => SetValue(SimulationProgressProperty, value);
  1022. }
  1023. // Methods
  1024. private static void SimulationProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  1025. {
  1026. var canvas = d as WrapperCanvas;
  1027. var newValue = (double) e.NewValue;
  1028. if (canvas != null && canvas.Children.Count > 0)
  1029. {
  1030. if (canvas.Children[0] is FrameworkElement element)
  1031. {
  1032. element.Width = Math.Max(0.0,
  1033. canvas.OldRect.Width * newValue + canvas.NewRect.Width * (1.0 - newValue));
  1034. element.Height = Math.Max(0.0,
  1035. canvas.OldRect.Height * newValue + canvas.NewRect.Height * (1.0 - newValue));
  1036. SetLeft(element, newValue * (canvas.OldRect.Left - canvas.NewRect.Left));
  1037. SetTop(element, newValue * (canvas.OldRect.Top - canvas.NewRect.Top));
  1038. }
  1039. }
  1040. }
  1041. }
  1042. }