Files
HandyControl/src/Shared/Microsoft.Expression.Interactions/ExtendedVisualStateManager.cs
T

1123 lines
46 KiB
C#

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using HandyControl.Data;
namespace HandyControl.Interactivity;
public class ExtendedVisualStateManager : VisualStateManager
{
// Fields
internal static readonly DependencyProperty CachedBackgroundProperty =
DependencyProperty.RegisterAttached("CachedBackground", typeof(object), typeof(ExtendedVisualStateManager),
new PropertyMetadata(null));
internal static readonly DependencyProperty CachedEffectProperty =
DependencyProperty.RegisterAttached("CachedEffect", typeof(Effect), typeof(ExtendedVisualStateManager),
new PropertyMetadata(null));
private static readonly List<DependencyProperty> ChildAffectingLayoutProperties;
internal static readonly DependencyProperty CurrentStateProperty =
DependencyProperty.RegisterAttached("CurrentState", typeof(VisualState), typeof(ExtendedVisualStateManager),
new PropertyMetadata(null));
internal static readonly DependencyProperty DidCacheBackgroundProperty =
DependencyProperty.RegisterAttached("DidCacheBackground", typeof(bool), typeof(ExtendedVisualStateManager),
new PropertyMetadata(ValueBoxes.FalseBox));
private static readonly List<DependencyProperty> LayoutProperties;
internal static readonly DependencyProperty LayoutStoryboardProperty =
DependencyProperty.RegisterAttached("LayoutStoryboard", typeof(Storyboard),
typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
private static Storyboard LayoutTransitionStoryboard;
private static List<FrameworkElement> MovingElements;
internal static readonly DependencyProperty OriginalLayoutValuesProperty =
DependencyProperty.RegisterAttached("OriginalLayoutValues", typeof(List<OriginalLayoutValueRecord>),
typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
public static readonly DependencyProperty RuntimeVisibilityPropertyProperty =
DependencyProperty.RegisterAttached("RuntimeVisibilityProperty", typeof(DependencyProperty),
typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
public static readonly DependencyProperty TransitionEffectProperty =
DependencyProperty.RegisterAttached("TransitionEffect", typeof(TransitionEffect),
typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
internal static readonly DependencyProperty TransitionEffectStoryboardProperty =
DependencyProperty.RegisterAttached("TransitionEffectStoryboard", typeof(Storyboard),
typeof(ExtendedVisualStateManager), new PropertyMetadata(null));
public static readonly DependencyProperty UseFluidLayoutProperty =
DependencyProperty.RegisterAttached("UseFluidLayout", typeof(bool), typeof(ExtendedVisualStateManager),
new PropertyMetadata(ValueBoxes.FalseBox));
private bool _changingState;
// Methods
static ExtendedVisualStateManager()
{
var list = new List<DependencyProperty>
{
Grid.ColumnProperty,
Grid.ColumnSpanProperty,
Grid.RowProperty,
Grid.RowSpanProperty,
Canvas.LeftProperty,
Canvas.TopProperty,
FrameworkElement.WidthProperty,
FrameworkElement.HeightProperty,
FrameworkElement.MinWidthProperty,
FrameworkElement.MinHeightProperty,
FrameworkElement.MaxWidthProperty,
FrameworkElement.MaxHeightProperty,
FrameworkElement.MarginProperty,
FrameworkElement.HorizontalAlignmentProperty,
FrameworkElement.VerticalAlignmentProperty,
UIElement.VisibilityProperty,
StackPanel.OrientationProperty
};
LayoutProperties = list;
var list2 = new List<DependencyProperty>
{
StackPanel.OrientationProperty
};
ChildAffectingLayoutProperties = list2;
}
// Properties
public static bool IsRunningFluidLayoutTransition =>
LayoutTransitionStoryboard != null;
private static void AnimateTransitionEffect(FrameworkElement stateGroupsRoot, VisualTransition transition)
{
var element = new DoubleAnimation
{
Duration = transition.GeneratedDuration,
EasingFunction = transition.GeneratedEasingFunction,
From = 0.0,
To = 1.0
};
var sb = new Storyboard
{
Duration = transition.GeneratedDuration,
Children = { element }
};
Storyboard.SetTarget(element, stateGroupsRoot);
Storyboard.SetTargetProperty(element,
new PropertyPath("(0).(1)", UIElement.EffectProperty, TransitionEffect.ProgressProperty));
if (stateGroupsRoot is Panel panel && panel.Background == null)
{
SetDidCacheBackground(panel, true);
TransferLocalValue(panel, Panel.BackgroundProperty, CachedBackgroundProperty);
panel.Background = Brushes.Transparent;
}
sb.Completed += delegate
{
if (Equals(GetTransitionEffectStoryboard(stateGroupsRoot), sb))
FinishTransitionEffectAnimation(stateGroupsRoot);
};
SetTransitionEffectStoryboard(stateGroupsRoot, sb);
sb.Begin();
}
private static object CacheLocalValueHelper(DependencyObject dependencyObject, DependencyProperty property)
{
return dependencyObject.ReadLocalValue(property);
}
private static void control_LayoutUpdated(object sender, EventArgs e)
{
if (LayoutTransitionStoryboard != null)
foreach (var element in MovingElements)
{
if (element.Parent is WrapperCanvas parent)
{
var layoutRect = GetLayoutRect(parent);
var newRect = parent.NewRect;
var renderTransform = parent.RenderTransform as TranslateTransform;
var num = renderTransform?.X ?? 0.0;
var num2 = renderTransform?.Y ?? 0.0;
var num3 = newRect.Left - layoutRect.Left;
var num4 = newRect.Top - layoutRect.Top;
if (Math.Abs(num - num3) > 0.001 || Math.Abs(num2 - num4) > 0.001)
{
if (renderTransform == null)
{
renderTransform = new TranslateTransform();
parent.RenderTransform = renderTransform;
}
renderTransform.X = num3;
renderTransform.Y = num4;
}
}
}
}
private static void CopyLayoutProperties(FrameworkElement source, FrameworkElement target, bool restoring)
{
var canvas = restoring ? (WrapperCanvas) source : (WrapperCanvas) target;
if (canvas.LocalValueCache == null)
canvas.LocalValueCache = new Dictionary<DependencyProperty, object>();
foreach (var property in LayoutProperties)
if (!ChildAffectingLayoutProperties.Contains(property))
if (restoring)
{
ReplaceCachedLocalValueHelper(target, property, canvas.LocalValueCache[property]);
}
else
{
var obj2 = target.GetValue(property);
var obj3 = CacheLocalValueHelper(source, property);
canvas.LocalValueCache[property] = obj3;
if (IsVisibilityProperty(property))
canvas.DestinationVisibilityCache = (Visibility) source.GetValue(property);
else
target.SetValue(property, source.GetValue(property));
source.SetValue(property, obj2);
}
}
private static Storyboard CreateLayoutTransitionStoryboard(VisualTransition transition,
List<FrameworkElement> movingElements, Dictionary<FrameworkElement, double> oldOpacities)
{
var duration = transition?.GeneratedDuration ?? new Duration(TimeSpan.Zero);
var generatedEasingFunction = transition?.GeneratedEasingFunction;
var storyboard = new Storyboard
{
Duration = duration
};
foreach (var element in movingElements)
{
if (element.Parent is WrapperCanvas parent)
{
var animation = new DoubleAnimation
{
From = 1.0,
To = 0.0,
Duration = duration,
EasingFunction = generatedEasingFunction
};
Storyboard.SetTarget(animation, parent);
Storyboard.SetTargetProperty(animation, new PropertyPath(WrapperCanvas.SimulationProgressProperty));
storyboard.Children.Add(animation);
parent.SimulationProgress = 1.0;
var newRect = parent.NewRect;
if (!IsClose(parent.Width, newRect.Width))
{
var animation3 = new DoubleAnimation
{
From = newRect.Width,
To = newRect.Width,
Duration = duration
};
Storyboard.SetTarget(animation3, parent);
Storyboard.SetTargetProperty(animation3, new PropertyPath(FrameworkElement.WidthProperty));
storyboard.Children.Add(animation3);
}
if (!IsClose(parent.Height, newRect.Height))
{
var animation5 = new DoubleAnimation
{
From = newRect.Height,
To = newRect.Height,
Duration = duration
};
Storyboard.SetTarget(animation5, parent);
Storyboard.SetTargetProperty(animation5, new PropertyPath(FrameworkElement.HeightProperty));
storyboard.Children.Add(animation5);
}
if (parent.DestinationVisibilityCache == Visibility.Collapsed)
{
var margin = parent.Margin;
if (!IsClose(margin.Left, 0.0) || !IsClose(margin.Top, 0.0) || !IsClose(margin.Right, 0.0) ||
!IsClose(margin.Bottom, 0.0))
{
var frames = new ObjectAnimationUsingKeyFrames
{
Duration = duration
};
var frame2 = new DiscreteObjectKeyFrame
{
KeyTime = TimeSpan.Zero
};
var thickness2 = new Thickness();
frame2.Value = thickness2;
var keyFrame = frame2;
frames.KeyFrames.Add(keyFrame);
Storyboard.SetTarget(frames, parent);
Storyboard.SetTargetProperty(frames, new PropertyPath(FrameworkElement.MarginProperty));
storyboard.Children.Add(frames);
}
if (!IsClose(parent.MinWidth, 0.0))
{
var animation7 = new DoubleAnimation
{
From = 0.0,
To = 0.0,
Duration = duration
};
Storyboard.SetTarget(animation7, parent);
Storyboard.SetTargetProperty(animation7,
new PropertyPath(FrameworkElement.MinWidthProperty));
storyboard.Children.Add(animation7);
}
if (!IsClose(parent.MinHeight, 0.0))
{
var animation9 = new DoubleAnimation
{
From = 0.0,
To = 0.0,
Duration = duration
};
Storyboard.SetTarget(animation9, parent);
Storyboard.SetTargetProperty(animation9,
new PropertyPath(FrameworkElement.MinHeightProperty));
storyboard.Children.Add(animation9);
}
}
}
}
foreach (var element2 in oldOpacities.Keys)
{
if (element2.Parent is WrapperCanvas canvas2)
{
var a = oldOpacities[element2];
var num2 = canvas2.DestinationVisibilityCache == Visibility.Visible ? 1.0 : 0.0;
if (!IsClose(a, 1.0) || !IsClose(num2, 1.0))
{
var animation11 = new DoubleAnimation
{
From = a,
To = num2,
Duration = duration,
EasingFunction = generatedEasingFunction
};
Storyboard.SetTarget(animation11, canvas2);
Storyboard.SetTargetProperty(animation11, new PropertyPath(UIElement.OpacityProperty));
storyboard.Children.Add(animation11);
}
}
}
return storyboard;
}
private static Storyboard ExtractLayoutStoryboard(VisualState state)
{
Storyboard layoutStoryboard = null;
if (state.Storyboard != null)
{
layoutStoryboard = GetLayoutStoryboard(state.Storyboard);
if (layoutStoryboard == null)
{
layoutStoryboard = new Storyboard();
for (var i = state.Storyboard.Children.Count - 1; i >= 0; i--)
{
var timeline = state.Storyboard.Children[i];
if (LayoutPropertyFromTimeline(timeline, false) != null)
{
state.Storyboard.Children.RemoveAt(i);
layoutStoryboard.Children.Add(timeline);
}
}
SetLayoutStoryboard(state.Storyboard, layoutStoryboard);
}
}
if (layoutStoryboard == null)
return new Storyboard();
return layoutStoryboard;
}
private static List<FrameworkElement> FindTargetElements(FrameworkElement control,
FrameworkElement templateRoot, Storyboard layoutStoryboard,
List<OriginalLayoutValueRecord> originalValueRecords, List<FrameworkElement> movingElements)
{
var list = new List<FrameworkElement>();
if (movingElements != null)
list.AddRange(movingElements);
foreach (var timeline in layoutStoryboard.Children)
{
var item = (FrameworkElement) GetTimelineTarget(control, templateRoot, timeline);
if (item != null)
{
if (!list.Contains(item))
list.Add(item);
if (ChildAffectingLayoutProperties.Contains(LayoutPropertyFromTimeline(timeline, false)))
{
if (item is Panel panel)
foreach (FrameworkElement element2 in panel.Children)
if (!list.Contains(element2) && !(element2 is WrapperCanvas))
list.Add(element2);
}
}
}
foreach (var record in originalValueRecords)
{
if (!list.Contains(record.Element))
list.Add(record.Element);
if (ChildAffectingLayoutProperties.Contains(record.Property))
{
if (record.Element is Panel element)
foreach (FrameworkElement element3 in element.Children)
if (!list.Contains(element3) && !(element3 is WrapperCanvas))
list.Add(element3);
}
}
for (var i = 0; i < list.Count; i++)
{
var reference = list[i];
var parent = VisualTreeHelper.GetParent(reference) as FrameworkElement;
if (movingElements != null && movingElements.Contains(reference) && parent is WrapperCanvas)
parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
if (parent != null)
{
if (!list.Contains(parent))
list.Add(parent);
for (var j = 0; j < VisualTreeHelper.GetChildrenCount(parent); j++)
{
if (VisualTreeHelper.GetChild(parent, j) is FrameworkElement child && !list.Contains(child) && !(child is WrapperCanvas))
list.Add(child);
}
}
}
return list;
}
private static VisualTransition FindTransition(VisualStateGroup group, VisualState previousState,
VisualState state)
{
var str = previousState != null ? previousState.Name : string.Empty;
var str2 = state != null ? state.Name : string.Empty;
var num = -1;
VisualTransition transition = null;
foreach (VisualTransition transition2 in group.Transitions)
{
var num2 = 0;
if (transition2.From == str)
num2++;
else if (!string.IsNullOrEmpty(transition2.From))
continue;
if (transition2.To == str2)
num2 += 2;
else if (!string.IsNullOrEmpty(transition2.To))
continue;
if (num2 > num)
{
num = num2;
transition = transition2;
}
}
return transition;
}
private static bool FinishesWithZeroOpacity(FrameworkElement control, FrameworkElement stateGroupsRoot,
VisualState state, VisualState previousState)
{
if (state.Storyboard != null)
foreach (var timeline in state.Storyboard.Children)
if (TimelineIsAnimatingRootOpacity(timeline, control, stateGroupsRoot))
{
var valueFromTimeline = GetValueFromTimeline(timeline, out var flag);
return flag && valueFromTimeline is double d && Math.Abs(d) < 0.001;
}
if (previousState?.Storyboard == null)
return Math.Abs(stateGroupsRoot.Opacity) < 0.001;
foreach (var timeline2 in previousState.Storyboard.Children)
TimelineIsAnimatingRootOpacity(timeline2, control, stateGroupsRoot);
var animationBaseValue = (double) stateGroupsRoot.GetAnimationBaseValue(UIElement.OpacityProperty);
return Math.Abs(animationBaseValue) < 0.001;
}
private static void FinishTransitionEffectAnimation(FrameworkElement stateGroupsRoot)
{
SetTransitionEffectStoryboard(stateGroupsRoot, null);
TransferLocalValue(stateGroupsRoot, CachedEffectProperty, UIElement.EffectProperty);
if (GetDidCacheBackground(stateGroupsRoot))
{
TransferLocalValue(stateGroupsRoot, CachedBackgroundProperty, Panel.BackgroundProperty);
SetDidCacheBackground(stateGroupsRoot, false);
}
}
internal static object GetCachedBackground(DependencyObject obj)
{
return obj.GetValue(CachedBackgroundProperty);
}
internal static Effect GetCachedEffect(DependencyObject obj)
{
return (Effect) obj.GetValue(CachedEffectProperty);
}
internal static VisualState GetCurrentState(DependencyObject obj)
{
return (VisualState) obj.GetValue(CurrentStateProperty);
}
internal static bool GetDidCacheBackground(DependencyObject obj)
{
return (bool) obj.GetValue(DidCacheBackgroundProperty);
}
internal static Rect GetLayoutRect(FrameworkElement element)
{
var actualWidth = element.ActualWidth;
var actualHeight = element.ActualHeight;
if (element is Image || element is MediaElement)
if (element.Parent is Canvas)
{
actualWidth = double.IsNaN(element.Width) ? actualWidth : element.Width;
actualHeight = double.IsNaN(element.Height) ? actualHeight : element.Height;
}
else
{
actualWidth = element.RenderSize.Width;
actualHeight = element.RenderSize.Height;
}
actualWidth = element.Visibility == Visibility.Collapsed ? 0.0 : actualWidth;
actualHeight = element.Visibility == Visibility.Collapsed ? 0.0 : actualHeight;
var margin = element.Margin;
var layoutSlot = LayoutInformation.GetLayoutSlot(element);
var x = 0.0;
var y = 0.0;
x = element.HorizontalAlignment switch
{
HorizontalAlignment.Left => layoutSlot.Left + margin.Left,
HorizontalAlignment.Center => (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 -
actualWidth / 2.0,
HorizontalAlignment.Right => layoutSlot.Right - margin.Right - actualWidth,
HorizontalAlignment.Stretch => Math.Max(layoutSlot.Left + margin.Left,
(layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - actualWidth / 2.0),
_ => x
};
y = element.VerticalAlignment switch
{
VerticalAlignment.Top => layoutSlot.Top + margin.Top,
VerticalAlignment.Center => (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 -
actualHeight / 2.0,
VerticalAlignment.Bottom => layoutSlot.Bottom - margin.Bottom - actualHeight,
VerticalAlignment.Stretch => Math.Max(layoutSlot.Top + margin.Top,
(layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - actualHeight / 2.0),
_ => y
};
return new Rect(x, y, actualWidth, actualHeight);
}
internal static Storyboard GetLayoutStoryboard(DependencyObject obj)
{
return (Storyboard) obj.GetValue(LayoutStoryboardProperty);
}
private static Dictionary<FrameworkElement, double> GetOldOpacities(FrameworkElement control,
FrameworkElement templateRoot, Storyboard layoutStoryboard,
List<OriginalLayoutValueRecord> originalValueRecords, List<FrameworkElement> movingElements)
{
var dictionary = new Dictionary<FrameworkElement, double>();
if (movingElements != null)
foreach (var element in movingElements)
{
if (element.Parent is WrapperCanvas parent)
dictionary.Add(element, parent.Opacity);
}
for (var i = originalValueRecords.Count - 1; i >= 0; i--)
{
var record = originalValueRecords[i];
if (IsVisibilityProperty(record.Property) && !dictionary.TryGetValue(record.Element, out var num2))
{
num2 = (Visibility) record.Element.GetValue(record.Property) == Visibility.Visible ? 1.0 : 0.0;
dictionary.Add(record.Element, num2);
}
}
foreach (var timeline in layoutStoryboard.Children)
{
var key = (FrameworkElement) GetTimelineTarget(control, templateRoot, timeline);
var property = LayoutPropertyFromTimeline(timeline, true);
if (key != null && IsVisibilityProperty(property) && !dictionary.TryGetValue(key, out var num3))
{
num3 = (Visibility) key.GetValue(property) == Visibility.Visible ? 1.0 : 0.0;
dictionary.Add(key, num3);
}
}
return dictionary;
}
internal static List<OriginalLayoutValueRecord> GetOriginalLayoutValues(DependencyObject obj)
{
return (List<OriginalLayoutValueRecord>) obj.GetValue(OriginalLayoutValuesProperty);
}
private static Dictionary<FrameworkElement, Rect> GetRectsOfTargets(IEnumerable<FrameworkElement> targets,
ICollection<FrameworkElement> movingElements)
{
var dictionary = new Dictionary<FrameworkElement, Rect>();
foreach (var element in targets)
{
Rect layoutRect;
if (movingElements != null && movingElements.Contains(element) && element.Parent is WrapperCanvas parent)
{
layoutRect = GetLayoutRect(parent);
var renderTransform = parent.RenderTransform as TranslateTransform;
var left = Canvas.GetLeft(element);
var top = Canvas.GetTop(element);
layoutRect = new Rect(
layoutRect.Left + (double.IsNaN(left) ? 0.0 : left) +
(renderTransform?.X ?? 0.0),
layoutRect.Top + (double.IsNaN(top) ? 0.0 : top) +
(renderTransform?.Y ?? 0.0), element.ActualWidth, element.ActualHeight);
}
else
{
layoutRect = GetLayoutRect(element);
}
dictionary.Add(element, layoutRect);
}
return dictionary;
}
public static DependencyProperty GetRuntimeVisibilityProperty(DependencyObject obj)
{
return (DependencyProperty) obj.GetValue(RuntimeVisibilityPropertyProperty);
}
private static object GetTimelineTarget(FrameworkElement control, FrameworkElement templateRoot,
Timeline timeline)
{
var targetName = Storyboard.GetTargetName(timeline);
if (string.IsNullOrEmpty(targetName))
return null;
if (control is UserControl)
return control.FindName(targetName);
return templateRoot.FindName(targetName);
}
public static TransitionEffect GetTransitionEffect(DependencyObject obj)
{
return (TransitionEffect) obj.GetValue(TransitionEffectProperty);
}
internal static Storyboard GetTransitionEffectStoryboard(DependencyObject obj)
{
return (Storyboard) obj.GetValue(TransitionEffectStoryboardProperty);
}
public static bool GetUseFluidLayout(DependencyObject obj)
{
return (bool) obj.GetValue(UseFluidLayoutProperty);
}
private static object GetValueFromTimeline(Timeline timeline, out bool gotValue)
{
if (timeline is ObjectAnimationUsingKeyFrames frames)
{
gotValue = true;
return frames.KeyFrames[0].Value;
}
if (timeline is DoubleAnimationUsingKeyFrames frames2)
{
gotValue = true;
return frames2.KeyFrames[0].Value;
}
if (timeline is DoubleAnimation animation)
{
gotValue = true;
return animation.To;
}
if (timeline is ThicknessAnimationUsingKeyFrames frames3)
{
gotValue = true;
return frames3.KeyFrames[0].Value;
}
if (timeline is ThicknessAnimation animation2)
{
gotValue = true;
return animation2.To;
}
if (timeline is Int32AnimationUsingKeyFrames frames4)
{
gotValue = true;
return frames4.KeyFrames[0].Value;
}
if (timeline is Int32Animation animation3)
{
gotValue = true;
return animation3.To;
}
gotValue = false;
return null;
}
protected override bool GoToStateCore(FrameworkElement control, FrameworkElement stateGroupsRoot,
string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
{
if (_changingState)
return false;
var currentState = GetCurrentState(group);
if (!Equals(currentState, state))
{
var transition = FindTransition(group, currentState, state);
var animateWithTransitionEffect =
PrepareTransitionEffectImage(stateGroupsRoot, useTransitions, transition);
if (!GetUseFluidLayout(group))
return TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
useTransitions, transition, animateWithTransitionEffect, currentState);
var layoutStoryboard = ExtractLayoutStoryboard(state);
var originalLayoutValues = GetOriginalLayoutValues(group);
if (originalLayoutValues == null)
{
originalLayoutValues = new List<OriginalLayoutValueRecord>();
SetOriginalLayoutValues(group, originalLayoutValues);
}
if (!useTransitions)
{
if (LayoutTransitionStoryboard != null)
StopAnimations();
var flag2 = TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
false, transition, animateWithTransitionEffect, currentState);
SetLayoutStoryboardProperties(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues);
return flag2;
}
if (layoutStoryboard.Children.Count == 0 && originalLayoutValues.Count == 0)
return TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
true, transition, animateWithTransitionEffect, currentState);
try
{
_changingState = true;
stateGroupsRoot.UpdateLayout();
var targets = FindTargetElements(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues,
MovingElements);
var rectsOfTargets = GetRectsOfTargets(targets, MovingElements);
var oldOpacities = GetOldOpacities(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues,
MovingElements);
if (LayoutTransitionStoryboard != null)
{
stateGroupsRoot.LayoutUpdated -= control_LayoutUpdated;
StopAnimations();
stateGroupsRoot.UpdateLayout();
}
TransitionEffectAwareGoToStateCore(control, stateGroupsRoot, stateName, group, state,
true, transition, animateWithTransitionEffect, currentState);
SetLayoutStoryboardProperties(control, stateGroupsRoot, layoutStoryboard, originalLayoutValues);
stateGroupsRoot.UpdateLayout();
var newRects = GetRectsOfTargets(targets, null);
MovingElements = new List<FrameworkElement>();
foreach (var element in targets)
if (rectsOfTargets[element] != newRects[element])
MovingElements.Add(element);
foreach (var element2 in oldOpacities.Keys)
if (!MovingElements.Contains(element2))
MovingElements.Add(element2);
WrapMovingElementsInCanvases(MovingElements, rectsOfTargets, newRects);
stateGroupsRoot.LayoutUpdated += control_LayoutUpdated;
LayoutTransitionStoryboard =
CreateLayoutTransitionStoryboard(transition, MovingElements, oldOpacities);
void Handler(object sender, EventArgs e)
{
stateGroupsRoot.LayoutUpdated -= control_LayoutUpdated;
StopAnimations();
}
LayoutTransitionStoryboard.Completed += Handler;
LayoutTransitionStoryboard.Begin();
}
finally
{
_changingState = false;
}
}
return true;
}
private static bool IsClose(double a, double b)
{
return Math.Abs(a - b) < 1E-07;
}
private static bool IsVisibilityProperty(DependencyProperty property)
{
if (property != UIElement.VisibilityProperty)
return property.Name == "RuntimeVisibility";
return true;
}
private static DependencyProperty LayoutPropertyFromTimeline(Timeline timeline, bool forceRuntimeProperty)
{
var targetProperty = Storyboard.GetTargetProperty(timeline);
if (targetProperty != null &&
targetProperty.PathParameters.Count != 0)
{
if (targetProperty.PathParameters[0] is DependencyProperty item)
{
if (item.Name == "RuntimeVisibility" &&
item.OwnerType.Name.EndsWith("DesignTimeProperties", StringComparison.Ordinal))
{
if (!LayoutProperties.Contains(item))
LayoutProperties.Add(item);
if (!forceRuntimeProperty)
return UIElement.VisibilityProperty;
return item;
}
if (item.Name == "RuntimeWidth" &&
item.OwnerType.Name.EndsWith("DesignTimeProperties", StringComparison.Ordinal))
{
if (!LayoutProperties.Contains(item))
LayoutProperties.Add(item);
if (!forceRuntimeProperty)
return FrameworkElement.WidthProperty;
return item;
}
if (item.Name == "RuntimeHeight" &&
item.OwnerType.Name.EndsWith("DesignTimeProperties", StringComparison.Ordinal))
{
if (!LayoutProperties.Contains(item))
LayoutProperties.Add(item);
if (!forceRuntimeProperty)
return FrameworkElement.HeightProperty;
return item;
}
if (LayoutProperties.Contains(item))
return item;
}
}
return null;
}
private static bool PrepareTransitionEffectImage(FrameworkElement stateGroupsRoot, bool useTransitions,
VisualTransition transition)
{
var effect = transition == null ? null : GetTransitionEffect(transition);
var flag = false;
if (effect != null)
{
effect = effect.CloneCurrentValue();
if (useTransitions)
{
flag = true;
var pixelWidth = (int) Math.Max(1.0, stateGroupsRoot.ActualWidth);
var pixelHeight = (int) Math.Max(1.0, stateGroupsRoot.ActualHeight);
var bitmap = new RenderTargetBitmap(pixelWidth, pixelHeight, 96.0, 96.0, PixelFormats.Pbgra32);
bitmap.Render(stateGroupsRoot);
var brush = new ImageBrush
{
ImageSource = bitmap
};
effect.OldImage = brush;
}
var transitionEffectStoryboard = GetTransitionEffectStoryboard(stateGroupsRoot);
if (transitionEffectStoryboard != null)
{
transitionEffectStoryboard.Stop();
FinishTransitionEffectAnimation(stateGroupsRoot);
}
if (useTransitions)
{
TransferLocalValue(stateGroupsRoot, UIElement.EffectProperty, CachedEffectProperty);
stateGroupsRoot.Effect = effect;
}
}
return flag;
}
private static void ReplaceCachedLocalValueHelper(FrameworkElement element, DependencyProperty property,
object value)
{
if (value == DependencyProperty.UnsetValue)
{
element.ClearValue(property);
}
else
{
if (value is BindingExpressionBase base2)
element.SetBinding(property, base2.ParentBindingBase);
else
element.SetValue(property, value);
}
}
internal static void SetCachedBackground(DependencyObject obj, object value)
{
obj.SetValue(CachedBackgroundProperty, value);
}
internal static void SetCachedEffect(DependencyObject obj, Effect value)
{
obj.SetValue(CachedEffectProperty, value);
}
internal static void SetCurrentState(DependencyObject obj, VisualState value)
{
obj.SetValue(CurrentStateProperty, value);
}
internal static void SetDidCacheBackground(DependencyObject obj, bool value)
{
obj.SetValue(DidCacheBackgroundProperty, ValueBoxes.BooleanBox(value));
}
internal static void SetLayoutStoryboard(DependencyObject obj, Storyboard value)
{
obj.SetValue(LayoutStoryboardProperty, value);
}
private static void SetLayoutStoryboardProperties(FrameworkElement control, FrameworkElement templateRoot,
Storyboard layoutStoryboard, List<OriginalLayoutValueRecord> originalValueRecords)
{
foreach (var record in originalValueRecords)
ReplaceCachedLocalValueHelper(record.Element, record.Property, record.Value);
originalValueRecords.Clear();
foreach (var timeline in layoutStoryboard.Children)
{
var dependencyObject = (FrameworkElement) GetTimelineTarget(control, templateRoot, timeline);
var property = LayoutPropertyFromTimeline(timeline, true);
if (dependencyObject != null && property != null)
{
var valueFromTimeline = GetValueFromTimeline(timeline, out var flag);
if (flag)
{
var item = new OriginalLayoutValueRecord
{
Element = dependencyObject,
Property = property,
Value = CacheLocalValueHelper(dependencyObject, property)
};
originalValueRecords.Add(item);
dependencyObject.SetValue(property, valueFromTimeline);
}
}
}
}
internal static void SetOriginalLayoutValues(DependencyObject obj, List<OriginalLayoutValueRecord> value)
{
obj.SetValue(OriginalLayoutValuesProperty, value);
}
public static void SetRuntimeVisibilityProperty(DependencyObject obj, DependencyProperty value)
{
obj.SetValue(RuntimeVisibilityPropertyProperty, value);
}
public static void SetTransitionEffect(DependencyObject obj, TransitionEffect value)
{
obj.SetValue(TransitionEffectProperty, value);
}
internal static void SetTransitionEffectStoryboard(DependencyObject obj, Storyboard value)
{
obj.SetValue(TransitionEffectStoryboardProperty, value);
}
public static void SetUseFluidLayout(DependencyObject obj, bool value)
{
obj.SetValue(UseFluidLayoutProperty, ValueBoxes.BooleanBox(value));
}
private static void StopAnimations()
{
if (LayoutTransitionStoryboard != null)
{
LayoutTransitionStoryboard.Stop();
LayoutTransitionStoryboard = null;
}
if (MovingElements != null)
{
UnwrapMovingElementsFromCanvases(MovingElements);
MovingElements = null;
}
}
private static bool TimelineIsAnimatingRootOpacity(Timeline timeline, FrameworkElement control,
FrameworkElement stateGroupsRoot)
{
if (!Equals(GetTimelineTarget(control, stateGroupsRoot, timeline), stateGroupsRoot))
return false;
var targetProperty = Storyboard.GetTargetProperty(timeline);
return targetProperty != null &&
targetProperty.PathParameters.Count != 0 &&
targetProperty.PathParameters[0] == UIElement.OpacityProperty;
}
private static void TransferLocalValue(FrameworkElement element, DependencyProperty sourceProperty,
DependencyProperty destProperty)
{
var obj2 = CacheLocalValueHelper(element, sourceProperty);
ReplaceCachedLocalValueHelper(element, destProperty, obj2);
}
private bool TransitionEffectAwareGoToStateCore(FrameworkElement control, FrameworkElement stateGroupsRoot,
string stateName, VisualStateGroup group, VisualState state, bool useTransitions,
VisualTransition transition, bool animateWithTransitionEffect, VisualState previousState)
{
IEasingFunction generatedEasingFunction = null;
if (animateWithTransitionEffect)
{
generatedEasingFunction = transition.GeneratedEasingFunction;
var function2 = new DummyEasingFunction
{
DummyValue = FinishesWithZeroOpacity(control, stateGroupsRoot, state, previousState) ? 0.01 : 0.0
};
transition.GeneratedEasingFunction = function2;
}
var flag = base.GoToStateCore(control, stateGroupsRoot, stateName, group, state, useTransitions);
if (animateWithTransitionEffect)
{
transition.GeneratedEasingFunction = generatedEasingFunction;
if (flag)
AnimateTransitionEffect(stateGroupsRoot, transition);
}
SetCurrentState(group, state);
return flag;
}
private static void UnwrapMovingElementsFromCanvases(List<FrameworkElement> movingElements)
{
foreach (var element in movingElements)
{
if (element.Parent is WrapperCanvas parent)
{
var obj2 = CacheLocalValueHelper(element, FrameworkElement.DataContextProperty);
element.DataContext = element.DataContext;
var element2 = VisualTreeHelper.GetParent(parent) as FrameworkElement;
parent.Children.Remove(element);
if (element2 is Panel panel)
{
var index = panel.Children.IndexOf(parent);
panel.Children.RemoveAt(index);
panel.Children.Insert(index, element);
}
else
{
if (element2 is Decorator decorator)
decorator.Child = element;
}
CopyLayoutProperties(parent, element, true);
ReplaceCachedLocalValueHelper(element, FrameworkElement.DataContextProperty, obj2);
}
}
}
private static void WrapMovingElementsInCanvases(List<FrameworkElement> movingElements,
Dictionary<FrameworkElement, Rect> oldRects, Dictionary<FrameworkElement, Rect> newRects)
{
foreach (var element in movingElements)
{
var parent = VisualTreeHelper.GetParent(element) as FrameworkElement;
var canvas = new WrapperCanvas
{
OldRect = oldRects[element],
NewRect = newRects[element]
};
var obj2 = CacheLocalValueHelper(element, FrameworkElement.DataContextProperty);
element.DataContext = element.DataContext;
var flag = true;
if (parent is Panel panel && !panel.IsItemsHost)
{
var index = panel.Children.IndexOf(element);
panel.Children.RemoveAt(index);
panel.Children.Insert(index, canvas);
}
else
{
if (parent is Decorator decorator)
decorator.Child = canvas;
else
flag = false;
}
if (flag)
{
canvas.Children.Add(element);
CopyLayoutProperties(element, canvas, false);
ReplaceCachedLocalValueHelper(element, FrameworkElement.DataContextProperty, obj2);
}
}
}
// Nested Types
private class DummyEasingFunction : EasingFunctionBase
{
// Fields
public static readonly DependencyProperty DummyValueProperty = DependencyProperty.Register("DummyValue",
typeof(double), typeof(DummyEasingFunction), new PropertyMetadata(0.0));
// Properties
public double DummyValue
{
private get => (double) GetValue(DummyValueProperty);
set => SetValue(DummyValueProperty, value);
}
// Methods
protected override Freezable CreateInstanceCore()
{
return new DummyEasingFunction();
}
protected override double EaseInCore(double normalizedTime)
{
return DummyValue;
}
}
internal class OriginalLayoutValueRecord
{
// Properties
public FrameworkElement Element { get; set; }
public DependencyProperty Property { get; set; }
public object Value { get; set; }
}
internal class WrapperCanvas : Canvas
{
// Fields
internal static readonly DependencyProperty SimulationProgressProperty =
DependencyProperty.Register("SimulationProgress", typeof(double), typeof(WrapperCanvas),
new PropertyMetadata(0.0, SimulationProgressChanged));
// Properties
public Visibility DestinationVisibilityCache { get; set; }
public Dictionary<DependencyProperty, object> LocalValueCache { get; set; }
public Rect NewRect { get; set; }
public Rect OldRect { get; set; }
public double SimulationProgress
{
get =>
(double) GetValue(SimulationProgressProperty);
set => SetValue(SimulationProgressProperty, value);
}
// Methods
private static void SimulationProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var canvas = d as WrapperCanvas;
var newValue = (double) e.NewValue;
if (canvas != null && canvas.Children.Count > 0)
{
if (canvas.Children[0] is FrameworkElement element)
{
element.Width = Math.Max(0.0,
canvas.OldRect.Width * newValue + canvas.NewRect.Width * (1.0 - newValue));
element.Height = Math.Max(0.0,
canvas.OldRect.Height * newValue + canvas.NewRect.Height * (1.0 - newValue));
SetLeft(element, newValue * (canvas.OldRect.Left - canvas.NewRect.Left));
SetTop(element, newValue * (canvas.OldRect.Top - canvas.NewRect.Top));
}
}
}
}
}