├── CompositionAnimationToolkit ├── MakeNuget.bat ├── nuget.exe ├── CompositionExpression.cs ├── CompositionAnimationPropertyCollection.cs ├── CompositionAnimationToolkit.nuspec ├── CompositionAnimationExtensions.cs ├── Properties │ ├── AssemblyInfo.cs │ └── CompositionAnimationToolkit.rd.xml ├── TargetedExpressionAnimation.cs ├── TargetedCompositionAnimation.cs ├── KeyFrame.cs ├── TypeAnnotatedCompositionObject.cs ├── CompositionObjectExtensions.cs ├── CompositionPropertySetExtensions.cs ├── CompositionPropertySetWrapper.cs ├── TargetedCompositionKeyFrameAnimation.cs ├── ExpressionContext.cs ├── CompositionAnimationToolkit.csproj └── ExpressionHelper.cs ├── LICENSE ├── CompositionAnimationToolkit.sln ├── .gitattributes ├── .gitignore └── README.md /CompositionAnimationToolkit/MakeNuget.bat: -------------------------------------------------------------------------------- 1 | nuget pack CompositionAnimationToolkit.csproj -Prop Configuration=Release -------------------------------------------------------------------------------- /CompositionAnimationToolkit/nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aL3891/CompositionAnimationToolkit/HEAD/CompositionAnimationToolkit/nuget.exe -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionExpression.cs: -------------------------------------------------------------------------------- 1 | namespace CompositionAnimationToolkit 2 | { 3 | public class CompositionExpression 4 | { 5 | public string Expression { get; set; } 6 | public CompositionAnimationPropertyCollection Parameters { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionAnimationPropertyCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using Windows.UI.Composition; 5 | 6 | namespace CompositionAnimationToolkit 7 | { 8 | public class CompositionAnimationPropertyCollection : Dictionary 9 | { 10 | public CompositionObject Get(string property) => (CompositionObject)this[property]; 11 | 12 | public TypeAnnotatedCompositionObject Get(string property) => new TypeAnnotatedCompositionObject { Target = (CompositionObject)this[property] }; 13 | 14 | public TypeAnnotatedCompositionObject Get(Expression> expression) => new TypeAnnotatedCompositionObject { Target = (CompositionObject)this[ExpressionHelper.ExpressionToPropertyName(expression)] }; 15 | 16 | public R Get(T target, Expression> expression) => (R)this[ExpressionHelper.ExpressionToPropertyName(expression)]; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionAnimationToolkit.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | 0.0.8-beta 6 | $title$ 7 | Allan Lindqvist 8 | Allan Lindqvist 9 | https://github.com/aL3891/CompositionAnimationToolkit/blob/master/LICENSE 10 | https://github.com/aL3891/CompositionAnimationToolkit 11 | false 12 | A library for writing animations in the Windows.UI.Composition framework using statically typed lambdas 13 | 14 | Copyright 2016 15 | Animation Windows.UI.Composition Expressions Lambda 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Allan Lindqvist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionAnimationExtensions.cs: -------------------------------------------------------------------------------- 1 | using CompositionAnimationToolkit.Internal; 2 | using System; 3 | using System.Linq.Expressions; 4 | using Windows.UI.Composition; 5 | 6 | namespace CompositionAnimationToolkit 7 | { 8 | public static class CompositionAnimationExtensions 9 | { 10 | public static CompositionAnimationPropertyCollection ExpressionLambda(this ExpressionAnimation animation, Expression> expression) => 11 | ExpressionHelper.ExpressionLambda(animation, expression); 12 | 13 | public static CompositionAnimationPropertyCollection ExpressionLambda(this ExpressionAnimation animation, Expression, object>> expression) => 14 | ExpressionHelper.ExpressionLambda(animation, expression); 15 | 16 | public static KeyFrameAnimation InsertExpressionLambdaKeyFrame(this KeyFrameAnimation animation, float normalizedProgressKey, Expression> expression) => 17 | ExpressionHelper.InsertExpressionLambdaKeyFrame(animation, normalizedProgressKey, expression); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("CompositionAnimationToolkit")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("CompositionAnimationToolkit")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Version information for an assembly consists of the following four values: 17 | // 18 | // Major Version 19 | // Minor Version 20 | // Build Number 21 | // Revision 22 | // 23 | // You can specify all the values or you can default the Build and Revision Numbers 24 | // by using the '*' as shown below: 25 | // [assembly: AssemblyVersion("1.0.*")] 26 | [assembly: AssemblyVersion("0.0.8.0")] 27 | [assembly: AssemblyFileVersion("0.0.8.0")] 28 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /CompositionAnimationToolkit/TargetedExpressionAnimation.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using Windows.UI.Composition; 3 | 4 | namespace CompositionAnimationToolkit 5 | { 6 | public class TargetedExpressionAnimation : TargetedCompositionAnimation 7 | { 8 | private Expression animationexpression; 9 | 10 | private Expression expression; 11 | 12 | public TargetedExpressionAnimation(CompositionObject compositionObject, Expression expression, Expression animationexpression) 13 | { 14 | Target = compositionObject; 15 | this.expression = expression; 16 | this.animationexpression = animationexpression; 17 | } 18 | 19 | public override void EnsureAnimationCreated() 20 | { 21 | if (Animation == null) 22 | { 23 | TargetProperty = ExpressionHelper.ExpressionToPropertyName(expression); 24 | var animation = Target.Compositor.CreateExpressionAnimation(); 25 | 26 | var ce = ExpressionHelper.ExpressionToCompositionExpression(animationexpression); 27 | Properties = ce.Parameters; 28 | animation.Expression = ce.Expression; 29 | ExpressionHelper.ApplyParameters(Animation, ce.Parameters); 30 | 31 | Animation = animation; 32 | } 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/TargetedCompositionAnimation.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using Windows.UI.Composition; 3 | 4 | namespace CompositionAnimationToolkit 5 | { 6 | public class TargetedCompositionAnimation 7 | { 8 | public CompositionObject Target { get; set; } 9 | public string TargetProperty { get; set; } 10 | public CompositionAnimation Animation { get; set; } 11 | public CompositionAnimationPropertyCollection Properties { get; set; } 12 | 13 | public TargetedCompositionAnimation(CompositionObject compositionObject, Expression expression, CompositionAnimation animation) 14 | { 15 | Target = compositionObject; 16 | TargetProperty = ExpressionHelper.ExpressionToPropertyName(expression); 17 | Animation = animation; 18 | } 19 | 20 | public TargetedCompositionAnimation() 21 | { 22 | 23 | } 24 | 25 | public virtual void EnsureAnimationCreated() 26 | { 27 | 28 | } 29 | } 30 | 31 | public static class TargetedCompositionAnimationExtensions 32 | { 33 | public static T Start(this T animation) where T : TargetedCompositionAnimation 34 | { 35 | animation.EnsureAnimationCreated(); 36 | animation.Target.StartAnimation(animation.TargetProperty, animation.Animation); 37 | return animation; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/Properties/CompositionAnimationToolkit.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompositionAnimationToolkit", "CompositionAnimationToolkit\CompositionAnimationToolkit.csproj", "{B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|ARM = Debug|ARM 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|Any CPU = Release|Any CPU 15 | Release|ARM = Release|ARM 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|ARM.Build.0 = Debug|ARM 24 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|x64.ActiveCfg = Debug|x64 25 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|x64.Build.0 = Debug|x64 26 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|x86.ActiveCfg = Debug|x86 27 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Debug|x86.Build.0 = Debug|x86 28 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|ARM.ActiveCfg = Release|ARM 31 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|ARM.Build.0 = Release|ARM 32 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|x64.ActiveCfg = Release|x64 33 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|x64.Build.0 = Release|x64 34 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|x86.ActiveCfg = Release|x86 35 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F}.Release|x86.Build.0 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/KeyFrame.cs: -------------------------------------------------------------------------------- 1 | using CompositionAnimationToolkit.Internal; 2 | using System; 3 | using System.Linq.Expressions; 4 | using Windows.UI.Composition; 5 | 6 | namespace CompositionAnimationToolkit 7 | { 8 | public class KeyFrame 9 | { 10 | public static KeyFrame Create(T value) => new KeyFrame { Value = value }; 11 | public static KeyFrame CreateInferred(Expression> value) => new KeyFrame { Expression = ExpressionHelper.ExpressionToCompositionExpression(value) }; 12 | public static KeyFrame Create(Expression, T>> value) => new KeyFrame { Expression = ExpressionHelper.ExpressionToCompositionExpression(value) }; 13 | public static KeyFrame Create(Expression, T>> value) => new KeyFrame { Expression = ExpressionHelper.ExpressionToCompositionExpression(value) }; 14 | public static KeyFrame Create(double timestamp, T value, CompositionEasingFunction easing = null) => new KeyFrame { Value = value, TimeStamp = (float)timestamp, Easeing = easing }; 15 | public static KeyFrame CreateInferred(double timestamp, Expression> value, CompositionEasingFunction easing = null) => new KeyFrame { Expression = ExpressionHelper.ExpressionToCompositionExpression(value), TimeStamp = (float)timestamp, Easeing = easing }; 16 | public static KeyFrame Create(double timestamp, Expression, T>> value, CompositionEasingFunction easing = null) => new KeyFrame { Expression = ExpressionHelper.ExpressionToCompositionExpression(value), TimeStamp = (float)timestamp, Easeing = easing }; 17 | public static KeyFrame Create(double timestamp, Expression, T>> value, CompositionEasingFunction easing = null) => new KeyFrame { Expression = ExpressionHelper.ExpressionToCompositionExpression(value), TimeStamp = (float)timestamp, Easeing = easing }; 18 | } 19 | 20 | public class KeyFrame 21 | { 22 | private float timeStamp; 23 | 24 | public CompositionExpression Expression { get; set; } 25 | public TValue Value { get; set; } 26 | 27 | public CompositionEasingFunction Easeing { get; set; } 28 | public bool Floating { get; set; } = true; 29 | 30 | public float TimeStamp 31 | { 32 | get 33 | { 34 | return timeStamp; 35 | } 36 | set 37 | { 38 | timeStamp = value; 39 | Floating = false; 40 | } 41 | } 42 | 43 | internal KeyFrame() 44 | { 45 | 46 | } 47 | 48 | public static implicit operator KeyFrame(TValue value) => new KeyFrame { Value = value, timeStamp = -1 }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/TypeAnnotatedCompositionObject.cs: -------------------------------------------------------------------------------- 1 | using CompositionAnimationToolkit.Internal; 2 | using System; 3 | using System.Linq.Expressions; 4 | using System.Numerics; 5 | using Windows.UI; 6 | using Windows.UI.Composition; 7 | 8 | namespace CompositionAnimationToolkit 9 | { 10 | public class TypeAnnotatedCompositionObject 11 | { 12 | public CompositionObject Target { get; set; } 13 | 14 | public TargetedCompositionAnimation CreateAnimation(Expression> expression, CompositionAnimation animation) => new TargetedCompositionAnimation(Target, expression, animation); 15 | 16 | public TargetedCompositionAnimation CreateAnimation(Expression> expression, Expression, object>> animationexpression) => new TargetedExpressionAnimation(Target, expression, animationexpression); 17 | 18 | public TargetedKeyFrameAnimation CreateAnimation(Expression> expression, params KeyFrame[] values) => new TargetedKeyFrameAnimation(Target, expression, c => c.CreateScalarKeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 19 | public TargetedKeyFrameAnimation CreateAnimation(Expression> expression, params KeyFrame[] values) => new TargetedKeyFrameAnimation(Target, expression, c => c.CreateVector2KeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 20 | public TargetedKeyFrameAnimation CreateAnimation(Expression> expression, params KeyFrame[] values) => new TargetedKeyFrameAnimation(Target, expression, c => c.CreateVector3KeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 21 | public TargetedKeyFrameAnimation CreateAnimation(Expression> expression, params KeyFrame[] values) => new TargetedKeyFrameAnimation(Target, expression, c => c.CreateVector4KeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 22 | public TargetedKeyFrameAnimation CreateAnimation(Expression> expression, params KeyFrame[] values) => new TargetedKeyFrameAnimation(Target, expression, c => c.CreateQuaternionKeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 23 | public TargetedKeyFrameAnimation CreateAnimation(Expression> expression, params KeyFrame[] values) => new TargetedKeyFrameAnimation(Target, expression, c => c.CreateColorKeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 24 | 25 | public void StopAnimation(Expression> expression) 26 | { 27 | Target.StopAnimation(ExpressionHelper.ExpressionToPropertyName(expression)); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using CompositionAnimationToolkit.Internal; 2 | using System; 3 | using System.Linq.Expressions; 4 | using System.Numerics; 5 | using Windows.UI; 6 | using Windows.UI.Composition; 7 | 8 | namespace CompositionAnimationToolkit 9 | { 10 | public static class CompositionObjectExtensions 11 | { 12 | public static TargetedCompositionAnimation CreateAnimation(this T compositionObject, Expression> expression, CompositionAnimation animation) where T : CompositionObject => new TargetedCompositionAnimation(compositionObject, expression, animation); 13 | 14 | public static TargetedExpressionAnimation CreateAnimation(this T compositionObject, Expression> expression, Expression, object>> animationexpression) where T : CompositionObject => new TargetedExpressionAnimation(compositionObject, expression, animationexpression); 15 | 16 | public static TargetedKeyFrameAnimation CreateAnimation(this T compositionObject, Expression> expression, params KeyFrame[] values) where T : CompositionObject => new TargetedKeyFrameAnimation(compositionObject, expression, c => c.CreateScalarKeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 17 | public static TargetedKeyFrameAnimation CreateAnimation(this T compositionObject, Expression> expression, params KeyFrame[] values) where T : CompositionObject => new TargetedKeyFrameAnimation(compositionObject, expression, c => c.CreateVector2KeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 18 | public static TargetedKeyFrameAnimation CreateAnimation(this T compositionObject, Expression> expression, params KeyFrame[] values) where T : CompositionObject => new TargetedKeyFrameAnimation(compositionObject, expression, c => c.CreateVector3KeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 19 | public static TargetedKeyFrameAnimation CreateAnimation(this T compositionObject, Expression> expression, params KeyFrame[] values) where T : CompositionObject => new TargetedKeyFrameAnimation(compositionObject, expression, c => c.CreateVector4KeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 20 | public static TargetedKeyFrameAnimation CreateAnimation(this T compositionObject, Expression> expression, params KeyFrame[] values) where T : CompositionObject => new TargetedKeyFrameAnimation(compositionObject, expression, c => c.CreateQuaternionKeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 21 | public static TargetedKeyFrameAnimation CreateAnimation(this T compositionObject, Expression> expression, params KeyFrame[] values) where T : CompositionObject => new TargetedKeyFrameAnimation(compositionObject, expression, c => c.CreateColorKeyFrameAnimation(), (a, t, v, e) => a.InsertKeyFrame(t, v, e), values); 22 | 23 | public static void StopAnimation(this T compositionObject, Expression> expression) where T : CompositionObject 24 | { 25 | compositionObject.StopAnimation(ExpressionHelper.ExpressionToPropertyName(expression)); 26 | } 27 | 28 | public static TypeAnnotatedCompositionObject AsAnnotated(this CompositionObject input, R instance) => new TypeAnnotatedCompositionObject { Target = input }; 29 | public static TypeAnnotatedCompositionObject AsAnnotated(this CompositionObject input) => new TypeAnnotatedCompositionObject { Target = input }; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionPropertySetExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using System.Reflection; 4 | using Windows.UI; 5 | using Windows.UI.Composition; 6 | 7 | namespace CompositionAnimationToolkit 8 | { 9 | public static class CompositionPropertySetExtensions 10 | { 11 | public static T Get(this CompositionPropertySet propSet, string key) 12 | { 13 | var type = typeof(T); 14 | 15 | if (type == typeof(float)) 16 | { 17 | float res; 18 | if (propSet.TryGetScalar(key, out res) == CompositionGetValueStatus.Succeeded) 19 | return (T)(object)res; 20 | } 21 | else if (type == typeof(Vector2)) 22 | { 23 | Vector2 res; 24 | if (propSet.TryGetVector2(key, out res) == CompositionGetValueStatus.Succeeded) 25 | return (T)(object)res; 26 | } 27 | else if (type == typeof(Vector3)) 28 | { 29 | Vector3 res; 30 | if (propSet.TryGetVector3(key, out res) == CompositionGetValueStatus.Succeeded) 31 | return (T)(object)res; 32 | } 33 | else if (type == typeof(Vector4)) 34 | { 35 | Vector4 res; 36 | if (propSet.TryGetVector4(key, out res) == CompositionGetValueStatus.Succeeded) 37 | return (T)(object)res; 38 | } 39 | else if (type == typeof(Matrix3x2)) 40 | { 41 | Matrix3x2 res; 42 | if (propSet.TryGetMatrix3x2(key, out res) == CompositionGetValueStatus.Succeeded) 43 | return (T)(object)res; 44 | } 45 | else if (type == typeof(Matrix4x4)) 46 | { 47 | Matrix4x4 res; 48 | if (propSet.TryGetMatrix4x4(key, out res) == CompositionGetValueStatus.Succeeded) 49 | return (T)(object)res; 50 | } 51 | else if (type == typeof(Quaternion)) 52 | { 53 | Quaternion res; 54 | if (propSet.TryGetQuaternion(key, out res) == CompositionGetValueStatus.Succeeded) 55 | return (T)(object)res; 56 | } 57 | else if (type == typeof(Color)) 58 | { 59 | Color res; 60 | if (propSet.TryGetColor(key, out res) == CompositionGetValueStatus.Succeeded) 61 | return (T)(object)res; 62 | } 63 | 64 | throw new ArgumentException("Unsupported type"); 65 | } 66 | 67 | public static CompositionPropertySet ToPropertySet(object input, Compositor compositor) 68 | { 69 | var res = compositor.CreatePropertySet(); 70 | 71 | foreach (var p in input.GetType().GetTypeInfo().DeclaredProperties) 72 | { 73 | 74 | if (p.PropertyType == typeof(float)) 75 | res.InsertScalar(p.Name, (float)p.GetValue(input)); 76 | else if (p.PropertyType == typeof(double)) 77 | res.InsertScalar(p.Name, (float)(double)p.GetValue(input)); 78 | else if (p.PropertyType == typeof(int)) 79 | res.InsertScalar(p.Name, (int)p.GetValue(input)); 80 | else if (p.PropertyType == typeof(decimal)) 81 | res.InsertScalar(p.Name, (float)(decimal)p.GetValue(input)); 82 | else if (p.PropertyType == typeof(Vector2)) 83 | res.InsertVector2(p.Name, (Vector2)p.GetValue(input)); 84 | else if (p.PropertyType == typeof(Vector3)) 85 | res.InsertVector3(p.Name, (Vector3)p.GetValue(input)); 86 | else if (p.PropertyType == typeof(Vector4)) 87 | res.InsertVector4(p.Name, (Vector4)p.GetValue(input)); 88 | else if (p.PropertyType == typeof(Matrix3x2)) 89 | res.InsertMatrix3x2(p.Name, (Matrix3x2)p.GetValue(input)); 90 | else if (p.PropertyType == typeof(Matrix4x4)) 91 | res.InsertMatrix4x4(p.Name, (Matrix4x4)p.GetValue(input)); 92 | else if (p.PropertyType == typeof(Quaternion)) 93 | res.InsertQuaternion(p.Name, (Quaternion)p.GetValue(input)); 94 | else if (p.PropertyType == typeof(Color)) 95 | res.InsertColor(p.Name, (Color)p.GetValue(input)); 96 | } 97 | 98 | return res; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | # NuGet v3's project.json files produces more ignoreable files 154 | *.nuget.props 155 | *.nuget.targets 156 | 157 | # Microsoft Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Microsoft Azure Emulator 162 | ecf/ 163 | rcf/ 164 | 165 | # Microsoft Azure ApplicationInsights config file 166 | ApplicationInsights.config 167 | 168 | # Windows Store app package directory 169 | AppPackages/ 170 | BundleArtifacts/ 171 | 172 | # Visual Studio cache files 173 | # files ending in .cache can be ignored 174 | *.[Cc]ache 175 | # but keep track of directories ending in .cache 176 | !*.[Cc]ache/ 177 | 178 | # Others 179 | ClientBin/ 180 | ~$* 181 | *~ 182 | *.dbmdl 183 | *.dbproj.schemaview 184 | *.pfx 185 | *.publishsettings 186 | node_modules/ 187 | orleans.codegen.cs 188 | 189 | # RIA/Silverlight projects 190 | Generated_Code/ 191 | 192 | # Backup & report files from converting an old project file 193 | # to a newer Visual Studio version. Backup files are not needed, 194 | # because we have git ;-) 195 | _UpgradeReport_Files/ 196 | Backup*/ 197 | UpgradeLog*.XML 198 | UpgradeLog*.htm 199 | 200 | # SQL Server files 201 | *.mdf 202 | *.ldf 203 | 204 | # Business Intelligence projects 205 | *.rdl.data 206 | *.bim.layout 207 | *.bim_*.settings 208 | 209 | # Microsoft Fakes 210 | FakesAssemblies/ 211 | 212 | # GhostDoc plugin setting file 213 | *.GhostDoc.xml 214 | 215 | # Node.js Tools for Visual Studio 216 | .ntvs_analysis.dat 217 | 218 | # Visual Studio 6 build log 219 | *.plg 220 | 221 | # Visual Studio 6 workspace options file 222 | *.opt 223 | 224 | # Visual Studio LightSwitch build output 225 | **/*.HTMLClient/GeneratedArtifacts 226 | **/*.DesktopClient/GeneratedArtifacts 227 | **/*.DesktopClient/ModelManifest.xml 228 | **/*.Server/GeneratedArtifacts 229 | **/*.Server/ModelManifest.xml 230 | _Pvt_Extensions 231 | 232 | # Paket dependency manager 233 | .paket/paket.exe 234 | 235 | # FAKE - F# Make 236 | .fake/ 237 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionPropertySetWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using System.Runtime.CompilerServices; 4 | using Windows.UI; 5 | using Windows.UI.Composition; 6 | 7 | namespace CompositionAnimationToolkit 8 | { 9 | public class CompositionPropertySetWrapper 10 | { 11 | internal CompositionPropertySet PropertySet { get; set; } 12 | 13 | public CompositionPropertySetWrapper(Compositor copositor) 14 | { 15 | PropertySet = copositor.CreatePropertySet(); 16 | } 17 | 18 | public CompositionPropertySetWrapper(CompositionPropertySet propertySet) 19 | { 20 | PropertySet = propertySet; 21 | } 22 | 23 | public void StartAnimation(string propertyName, CompositionAnimation animation) 24 | { 25 | PropertySet.StartAnimation(propertyName, animation); 26 | } 27 | 28 | public void StopAnimation(string propertyName) 29 | { 30 | PropertySet.StopAnimation(propertyName); 31 | } 32 | 33 | protected Color GetColor([CallerMemberName]string key = "") 34 | { 35 | Color tmp; 36 | if (PropertySet.TryGetColor(key, out tmp) == CompositionGetValueStatus.Succeeded) 37 | return tmp; 38 | else 39 | throw new ArgumentException(key + " not found"); 40 | } 41 | 42 | protected Matrix3x2 GetMatrix3x2([CallerMemberName]string key = "") 43 | { 44 | Matrix3x2 tmp; 45 | if (PropertySet.TryGetMatrix3x2(key, out tmp) == CompositionGetValueStatus.Succeeded) 46 | return tmp; 47 | else 48 | throw new ArgumentException(key + " not found"); 49 | } 50 | 51 | protected Matrix4x4 GetMatrix4x4([CallerMemberName]string key = "") 52 | { 53 | Matrix4x4 tmp; 54 | if (PropertySet.TryGetMatrix4x4(key, out tmp) == CompositionGetValueStatus.Succeeded) 55 | return tmp; 56 | else 57 | throw new ArgumentException(key + " not found"); 58 | } 59 | 60 | protected Quaternion GetQuaternion([CallerMemberName]string key = "") 61 | { 62 | Quaternion tmp; 63 | if (PropertySet.TryGetQuaternion(key, out tmp) == CompositionGetValueStatus.Succeeded) 64 | return tmp; 65 | else 66 | throw new ArgumentException(key + " not found"); 67 | } 68 | 69 | protected float GetScalar([CallerMemberName]string key = "") 70 | { 71 | float tmp; 72 | if (PropertySet.TryGetScalar(key, out tmp) == CompositionGetValueStatus.Succeeded) 73 | return tmp; 74 | else 75 | throw new ArgumentException(key + " not found"); 76 | } 77 | 78 | protected Vector2 GetVector2([CallerMemberName]string key = "") 79 | { 80 | Vector2 tmp; 81 | if (PropertySet.TryGetVector2(key, out tmp) == CompositionGetValueStatus.Succeeded) 82 | return tmp; 83 | else 84 | throw new ArgumentException(key + " not found"); 85 | } 86 | 87 | protected Vector3 GetVector3([CallerMemberName]string key = "") 88 | { 89 | Vector3 tmp; 90 | if (PropertySet.TryGetVector3(key, out tmp) == CompositionGetValueStatus.Succeeded) 91 | return tmp; 92 | else 93 | throw new ArgumentException(key + " not found"); 94 | } 95 | 96 | protected Vector4 GetVector4([CallerMemberName]string key = "") 97 | { 98 | Vector4 tmp; 99 | if (PropertySet.TryGetVector4(key, out tmp) == CompositionGetValueStatus.Succeeded) 100 | return tmp; 101 | else 102 | throw new ArgumentException(key + " not found"); 103 | } 104 | 105 | protected void SetValue(Color value, [CallerMemberName]string key = "") 106 | { 107 | PropertySet.InsertColor(key, value); 108 | } 109 | 110 | protected void SetValue(Matrix3x2 value, [CallerMemberName]string key = "") 111 | { 112 | PropertySet.InsertMatrix3x2(key, value); 113 | } 114 | 115 | protected void SetValue(Matrix4x4 value, [CallerMemberName]string key = "") 116 | { 117 | PropertySet.InsertMatrix4x4(key, value); 118 | } 119 | 120 | protected void SetValue(Quaternion value, [CallerMemberName]string key = "") 121 | { 122 | PropertySet.InsertQuaternion(key, value); 123 | } 124 | 125 | protected void SetValue(float value, [CallerMemberName]string key = "") 126 | { 127 | PropertySet.InsertScalar(key, value); 128 | } 129 | 130 | protected void SetValue(Vector2 value, [CallerMemberName]string key = "") 131 | { 132 | PropertySet.InsertVector2(key, value); 133 | } 134 | 135 | protected void SetValue(Vector3 value, [CallerMemberName]string key = "") 136 | { 137 | PropertySet.InsertVector3(key, value); 138 | } 139 | 140 | protected void SetValue(Vector4 value, [CallerMemberName]string key = "") 141 | { 142 | PropertySet.InsertVector4(key, value); 143 | } 144 | } 145 | 146 | public static class CompositionPropertySetWrapperExtensions 147 | { 148 | public static TypeAnnotatedCompositionObject ToPropertySet(this T compositionObject) where T : CompositionPropertySetWrapper => new TypeAnnotatedCompositionObject { Target = compositionObject.PropertySet }; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/TargetedCompositionKeyFrameAnimation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using Windows.UI.Composition; 6 | 7 | namespace CompositionAnimationToolkit 8 | { 9 | public class TargetedKeyFrameAnimation : TargetedCompositionAnimation where Tanimation : KeyFrameAnimation 10 | { 11 | Func createAnimation; 12 | 13 | Action insertEasingKey; 14 | 15 | Expression expression; 16 | int duration = 500; 17 | int count = 1; 18 | List> Values; 19 | private int delay; 20 | 21 | internal TargetedKeyFrameAnimation(CompositionObject compositionObject, Expression expression, Func createAnimation, Action insertEasingKey, KeyFrame[] values) 22 | { 23 | this.createAnimation = createAnimation; 24 | this.insertEasingKey = insertEasingKey; 25 | Target = compositionObject; 26 | this.expression = expression; 27 | Values = values.ToList(); 28 | 29 | DistributeKeyFrames(); 30 | } 31 | 32 | private void DistributeKeyFrames() 33 | { 34 | var length = Values.Count; 35 | 36 | if (length > 0) 37 | { 38 | float start = 0, end = 1; 39 | int startIndex = 0, endIndex = length - 1; 40 | 41 | for (int i = 0; i < length; i++) 42 | { 43 | if (Values[i].Floating) 44 | { 45 | var next = Values.Skip(i + 1).FirstOrDefault(k => !k.Floating); 46 | if (next != null) 47 | { 48 | endIndex = Values.IndexOf(next); 49 | end = next.TimeStamp; 50 | } 51 | else 52 | { 53 | endIndex = length - 1; 54 | end = 1; 55 | } 56 | 57 | Values[i].TimeStamp = Lerp(start, end, Normalize(startIndex, endIndex, i)); 58 | Values[i].Floating = true; 59 | } 60 | else 61 | { 62 | startIndex = i; 63 | start = Values[i].TimeStamp; 64 | } 65 | } 66 | } 67 | } 68 | 69 | public int Count => Values.Count; 70 | 71 | public KeyFrame this[int index] => Values[index]; 72 | 73 | private float Normalize(float min, float max, float pos) => (pos - min) / (max - min); 74 | 75 | private float Lerp(float value1, float value2, float pos) => (1 - pos) * value1 + pos * value2; 76 | 77 | public override void EnsureAnimationCreated() 78 | { 79 | if (Animation == null) 80 | { 81 | Values = Values.OrderBy(k => k.TimeStamp).ToList(); 82 | DistributeKeyFrames(); 83 | 84 | var ani = createAnimation(Target.Compositor); 85 | TargetProperty = ExpressionHelper.ExpressionToPropertyName(expression); 86 | 87 | if (Values.Count == 1) 88 | Values[0].TimeStamp = 1; 89 | 90 | foreach (var item in Values) 91 | insertEasingKey(ani, item.TimeStamp, item.Value, item.Easeing); 92 | 93 | 94 | ani.Duration = TimeSpan.FromMilliseconds(duration); 95 | ani.DelayTime = TimeSpan.FromMilliseconds(delay); 96 | if (count > 0) 97 | { 98 | ani.IterationBehavior = AnimationIterationBehavior.Count; 99 | ani.IterationCount = count; 100 | } 101 | else 102 | ani.IterationBehavior = AnimationIterationBehavior.Forever; 103 | 104 | Animation = ani; 105 | } 106 | } 107 | 108 | 109 | public TargetedKeyFrameAnimation InsertKeyframe(KeyFrame keyFrame) 110 | { 111 | if (keyFrame.TimeStamp < 0) 112 | { 113 | keyFrame.TimeStamp = 1; 114 | keyFrame.Floating = true; 115 | } 116 | 117 | Values.Add(keyFrame); 118 | 119 | Values = Values.OrderBy(k => k.TimeStamp).ToList(); 120 | DistributeKeyFrames(); 121 | return this; 122 | } 123 | 124 | public TargetedKeyFrameAnimation EaseIn(CompositionEasingFunction func) 125 | { 126 | Values.First().Easeing = func; 127 | return this; 128 | } 129 | 130 | public TargetedKeyFrameAnimation EaseOut(CompositionEasingFunction func) 131 | { 132 | Values.Last().Easeing = func; 133 | return this; 134 | } 135 | 136 | public TargetedKeyFrameAnimation Duration(int time) 137 | { 138 | duration = time; 139 | return this; 140 | } 141 | 142 | public TargetedKeyFrameAnimation Delay(int time) 143 | { 144 | delay = time; 145 | return this; 146 | } 147 | 148 | public TargetedKeyFrameAnimation Loop(int c) 149 | { 150 | count = c; 151 | return this; 152 | } 153 | 154 | public TargetedKeyFrameAnimation Loop() 155 | { 156 | count = -1; 157 | return this; 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/ExpressionContext.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using Windows.UI; 3 | 4 | namespace CompositionAnimationToolkit.Internal 5 | { 6 | public class ExpressionContext 7 | { 8 | protected ExpressionContext() 9 | { 10 | 11 | } 12 | 13 | public float Abs(float value) => 0; 14 | public Vector2 Abs(Vector2 value) => new Vector2(0); 15 | public Vector3 Abs(Vector3 value) => new Vector3(0); 16 | public Vector4 Abs(Vector4 value) => new Vector4(0); 17 | public float Acos(float value) => 0; 18 | public float Asin(float value) => 0; 19 | public float Atan(float value) => 0; 20 | public float Ceiling(float value) => 0; 21 | public float Clamp(float value, float min, float max) => 0; 22 | public Color ColorLerp(Color ColorTo, Color ColorFrom, float Progression) => default(Color); 23 | public Color ColorLerpHSL(Color ColorTo, Color ColorFrom, float Progression) => default(Color); 24 | public Color ColorLerpRGB(Color ColorTo, Color ColorFrom, float Progression) => default(Color); 25 | public Quaternion Concatenate(Quaternion value, Quaternion value2) => default(Quaternion); 26 | public float Cos(float value) => 0; 27 | public Vector2 Distance(Vector2 value1, Vector2 value2) => default(Vector2); 28 | public Vector3 Distance(Vector3 value1, Vector3 value2) => default(Vector3); 29 | public Vector4 Distance(Vector4 value1, Vector4 value2) => default(Vector4); 30 | public float DistanceSquared(Vector2 value1, Vector2 value2) => 0; 31 | public float DistanceSquared(Vector3 value1, Vector3 value2) => 0; 32 | public float DistanceSquared(Vector4 value1, Vector4 value2) => 0; 33 | public float Floor(float value) => 0; 34 | public Vector2 Inverse(Vector2 value) => default(Vector2); 35 | public Vector3 Inverse(Vector3 value) => default(Vector3); 36 | public Vector4 Inverse(Vector4 value) => default(Vector4); 37 | public Vector2 Length(Vector2 value) => default(Vector2); 38 | public Vector3 Length(Vector3 value) => default(Vector3); 39 | public Vector4 Length(Vector4 value) => default(Vector4); 40 | public Vector2 LengthSquared(Vector2 value) => default(Vector2); 41 | public Vector3 LengthSquared(Vector3 value) => default(Vector3); 42 | public Vector4 LengthSquared(Vector4 value) => default(Vector4); 43 | public Vector2 Lerp(Vector2 value1, Vector2 value2, float progress) => default(Vector2); 44 | public Vector3 Lerp(Vector3 value1, Vector3 value2, float progress) => default(Vector3); 45 | public Vector4 Lerp(Vector4 value1, Vector4 value2, float progress) => default(Vector4); 46 | public Matrix3x2 Lerp(Matrix3x2 value1, Matrix3x2 value2, float progress) => default(Matrix3x2); 47 | public Matrix4x4 Lerp(Matrix4x4 value1, Matrix4x4 value2, float progress) => default(Matrix4x4); 48 | public float Ln(float value) => 0; 49 | public float Log10(float value) => 0; 50 | public Matrix3x2 Matrix3x2(float M11, float M12, float M21, float M22, float M31, float M32) => default(Matrix3x2); 51 | public Matrix3x2 Matrix3x2CreateFromScale(Vector2 scale) => default(Matrix3x2); 52 | public Matrix3x2 Matrix3x2CreateFromTranslation(Vector2 translation) => default(Matrix3x2); 53 | public Matrix4x4 Matrix4x4( 54 | float M11, float M12, float M13, float M14, 55 | float M21, float M22, float M23, float M24, 56 | float M31, float M32, float M33, float M34, 57 | float M41, float M42, float M43, float M44) => default(Matrix4x4); 58 | 59 | public Matrix4x4 Matrix4x4CreateFromScale(Vector3 scale) => default(Matrix4x4); 60 | public Matrix4x4 Matrix4x4CreateFromTranslation(Vector3 translation) => default(Matrix4x4); 61 | public Matrix4x4 Matrix4x4CreateFromAxisAngle(Vector3 axis, float angle) => default(Matrix4x4); 62 | public float Max(float value1, float value2) => 0; 63 | public float Min(float value1, float value2) => 0; 64 | public float Mod(float dividend, float divisor) => 0; 65 | public float Normalize() => 0; 66 | public Vector2 Normalize(Vector2 value) => default(Vector2); 67 | public Vector3 Normalize(Vector3 value) => default(Vector3); 68 | public Vector4 Normalize(Vector4 value) => default(Vector4); 69 | public float Pow(float value, int power) => 0; 70 | public Quaternion QuaternionCreateFromAxisAngle(Vector3 axis, float angle) => default(Quaternion); 71 | public float Round(float value) => 0; 72 | public Vector2 Scale(Vector2 value, float factor) => default(Vector2); 73 | public Vector3 Scale(Vector3 value, float factor) => default(Vector3); 74 | public Vector4 Scale(Vector4 value, float factor) => default(Vector4); 75 | public Matrix3x2 Scale(Matrix3x2 value, float factor) => default(Matrix3x2); 76 | public Matrix4x4 Scale(Matrix4x4 value, float factor) => default(Matrix4x4); 77 | public float Sin(float value) => 0; 78 | public Quaternion Slerp(Quaternion value1, Quaternion value2, float progress) => default(Quaternion); 79 | public float Sqrt(float value) => 0; 80 | public float Square(float value) => 0; 81 | public float Tan(float value) => 0; 82 | public float ToDegrees(float radians) => 0; 83 | public float ToRadians(float degrees) => 0; 84 | public Vector2 Transform(Vector2 value, Matrix3x2 matrix) => default(Vector2); 85 | public Vector4 Transform(Vector4 value, Matrix4x4 matrix) => default(Vector4); 86 | public Vector2 Vector2(float x, float y) => default(Vector2); 87 | public Vector3 Vector3(float x, float y, float z) => default(Vector3); 88 | public Vector4 Vector4(float x, float y, float z, float w) => default(Vector4); 89 | } 90 | 91 | public class ExpressionContext : ExpressionContext 92 | { 93 | public TProperty StartingValue { get; set; } 94 | public TProperty EndValue { get; set; } 95 | public TTarget Target { get; set; } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Composition Animation Toolkit 2 | 3 | The Composition animation toolkit is a set of tools that is ment to make working with animations in the Windows.Ui.Composition libraries easier. Specifically, it allows users to write animation expressions 4 | using statically typed lambda expressions instead of strings. It also has features to make working with property sets easier, such as providing a wrapper that user classes can derive from to make static properties for the contents in the property set, as well as generating property sets from any other class, including anonymous classes. 5 | 6 | ## Lambda expressions 7 | Typically expressions are written as strings, and any symbols used in the expressions will have to be added later. Using the extension methods in this library a c# lambda can be used to devine the expression instead. The lambda can close over variables in the surronding context and add them to the expression automatically. 8 | 9 | A typical expression can look like this: 10 | 11 | CompositionPropertySet propertySet = compositor.CreatePropertySet(); 12 | propertySet.InsertScalar("Rotation", 0f); 13 | propertySet.InsertVector3("CenterPointOffset", new Vector3(redSprite.Size.X / 2 - blueSprite.Size.X / 2, 14 | redSprite.Size.Y / 2 - blueSprite.Size.Y / 2, 0)); 15 | 16 | expressionAnimation.Expression = "visual.Offset + " + 17 | "propertySet.CenterPointOffset + " + 18 | "Vector3(cos(ToRadians(propertySet.Rotation)) * 150," + 19 | "sin(ToRadians(propertySet.Rotation)) * 75, 0)"; 20 | 21 | expressionAnimation.SetReferenceParameter("propertySet", propertySet); 22 | expressionAnimation.SetReferenceParameter("visual", redSprite); 23 | 24 | Using the a lambda expression this can instead be written as 25 | 26 | expressionAnimation.ExpressionLambda(c => redSprite.Offset + propertySet.Get("CenterPointOffset") 27 | + c.Vector3(c.Cos(c.ToRadians(propertySet.Get("Rotation"))) * 150, c.Sin(c.ToRadians(propertySet.Get("Rotation"))) * 75, 0)); 28 | 29 | And the SetReferenceParameter calls can be left out. 30 | 31 | Additionally, the property set can be defined as anonymous class instead: 32 | 33 | var propertySet = new 34 | { 35 | Rotation = 0, 36 | CenterPointOffset = new Vector3(redSprite.Size.X / 2 - blueSprite.Size.X / 2, redSprite.Size.Y / 2 - blueSprite.Size.Y / 2, 0) 37 | }; 38 | 39 | The expression can then be written as: 40 | 41 | expressionAnimation.ExpressionLambda(c => redSprite.Offset + propertySet.CenterPointOffset 42 | + c.Vector3(c.Cos(c.ToRadians(propertySet.Rotation)) * 150, c.Sin(c.ToRadians(propertySet.Rotation)) * 75, 0)); 43 | 44 | To be able to pass around property sets, there is also a class called CompositionPropertySetWrapper that can be derived from. An example of such a class can be: 45 | 46 | public class MyPropertySet : CompositionPropertySetWrapper 47 | { 48 | public MyPropertySet(Compositor comp) : base(comp) { } 49 | public float Rotation { get { return GetScalar(); } set { SetValue(value); } } 50 | public Vector3 CenterPointOffset { get { return GetVector3(); } set { SetValue(value); } } 51 | } 52 | 53 | It could then be used as above. The system will either use the wrapped property set or make a new property set and use that in the animation. 54 | The ExpressionLambda will also return a dictionary with all the parameters used in the expression so they can be used to start animations for example: 55 | 56 | var props = expressionAnimation.ExpressionLambda(...); 57 | ((CompositionPropertySet)props["propertySet"]).StartAnimation("Rotation", rotAnimation); 58 | 59 | ## Starting animations with a lambda 60 | It's now possible to start/stop animations using a lambda as well: 61 | 62 | blueSprite.StartAnimation(r => r.Offset, expressionAnimation); 63 | 64 | ## Starting animations with an inline expression 65 | It's now possible to start animations with an inline expression: 66 | 67 | blueSprite.StartAnimation(r => r.Offset, c => redSprite.Offset + otherVisual.Offset); 68 | 69 | ## Strongly typed this.* properties 70 | The this.startingvalue, this.endvalue and this.target properies in expressions are now supported by supplying those types when creating the depression. Additionally, new overloads for startanimation has been added that take an expeession direct and infer those types. 71 | 72 | blueSprite.StartAnimation(r => r.Offset, c => redSprite.Offset + c.StartingValue); 73 | 74 | ## Type annotated property sets 75 | You can now supply a type for an existing properyset to use when creating an expression. This is useful you get a propertyset from somewhere else or if you want to animate a propery inside a propertyset. 76 | 77 | properties.AsAnnotated().StartAnimation(c => c.Value1, c => c.Target.Value2 + 2); 78 | 79 | 80 | ## Type inferred key frame animations and fluent api 81 | Typically, creating keyframe animations requires a few diffrent method calls: 82 | 83 | Vector3KeyFrameAnimation offsetAnimation = compositor.CreateVector3KeyFrameAnimation(); 84 | offsetAnimation.InsertKeyFrame(0.0f, new Vector3(0, 0, 0)); 85 | offsetAnimation.InsertKeyFrame(0.5f, new Vector3(0, 0, -2000)); 86 | offsetAnimation.InsertKeyFrame(1.0f, new Vector3(0, 0, 0)); 87 | offsetAnimation.Duration = TimeSpan.FromMilliseconds(8000); 88 | offsetAnimation.IterationBehavior = AnimationIterationBehavior.Forever; 89 | visual.StartAnimation("Offset", offsetAnimation); 90 | 91 | using the new apis this can instead be written as 92 | 93 | visual.StartAnimation(r => r.Offset, new Vector3(0, 0, 0), new Vector3(0, 0, -2000), new Vector3(0, 0, 0)).Duration(8000).Loop(); 94 | 95 | This will infer the type of the property from the expression and create and create the correct keyframe type. it will then add the values as keyframes evenly spaced out across the duration. 96 | 97 | ## Future work 98 | This library has partially been validated against the samples in https://github.com/Microsoft/WindowsUIDevLabs (in this branch https://github.com/aL3891/WindowsUIDevLabs) but that work is not complete. 99 | In addition i'd like to look at if story boards can perhaps be converted to composition animations. Another idea is to implement currently unsupported functions like dot product as expanded expressions. 100 | 101 | If you have any ideas for things you'd like to see, or any other feedback, please do create an issue! 102 | 103 | ## Nuget 104 | This library is now on nuget! 105 | 106 | Install-Package CompositionAnimationToolkit -Pre 107 | 108 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/CompositionAnimationToolkit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B1E26B67-D32C-4E05-9FE4-6DD9C6EC1E4F} 8 | Library 9 | Properties 10 | CompositionAnimationToolkit 11 | CompositionAnimationToolkit 12 | en-US 13 | UAP 14 | 10.0.17134.0 15 | 10.0.15063.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | prompt 38 | 4 39 | 40 | 41 | x86 42 | true 43 | bin\x86\Debug\ 44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 45 | ;2008 46 | full 47 | x86 48 | false 49 | prompt 50 | 51 | 52 | x86 53 | bin\x86\Release\ 54 | TRACE;NETFX_CORE;WINDOWS_UWP 55 | true 56 | ;2008 57 | pdbonly 58 | x86 59 | false 60 | prompt 61 | 62 | 63 | ARM 64 | true 65 | bin\ARM\Debug\ 66 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 67 | ;2008 68 | full 69 | ARM 70 | false 71 | prompt 72 | 73 | 74 | ARM 75 | bin\ARM\Release\ 76 | TRACE;NETFX_CORE;WINDOWS_UWP 77 | true 78 | ;2008 79 | pdbonly 80 | ARM 81 | false 82 | prompt 83 | 84 | 85 | x64 86 | true 87 | bin\x64\Debug\ 88 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 89 | ;2008 90 | full 91 | x64 92 | false 93 | prompt 94 | 95 | 96 | x64 97 | bin\x64\Release\ 98 | TRACE;NETFX_CORE;WINDOWS_UWP 99 | true 100 | ;2008 101 | pdbonly 102 | x64 103 | false 104 | prompt 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 6.1.7 125 | 126 | 127 | 1.23.0 128 | 129 | 130 | 131 | 14.0 132 | 133 | 134 | 141 | -------------------------------------------------------------------------------- /CompositionAnimationToolkit/ExpressionHelper.cs: -------------------------------------------------------------------------------- 1 | using CompositionAnimationToolkit.Internal; 2 | using System; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Numerics; 6 | using System.Reflection; 7 | using Windows.UI; 8 | using Windows.UI.Composition; 9 | 10 | namespace CompositionAnimationToolkit 11 | { 12 | internal static class ExpressionHelper 13 | { 14 | internal static CompositionAnimationPropertyCollection ExpressionLambda(ExpressionAnimation animation, Expression expression) 15 | { 16 | var ce = ExpressionToCompositionExpression(expression); 17 | animation.Expression = ce.Expression; 18 | ApplyParameters(animation, ce.Parameters); 19 | return ce.Parameters; 20 | } 21 | 22 | internal static KeyFrameAnimation InsertExpressionLambdaKeyFrame(KeyFrameAnimation animation, float normalizedProgressKey, Expression expression) 23 | { 24 | var ce = ExpressionToCompositionExpression(expression); 25 | animation.InsertExpressionKeyFrame(normalizedProgressKey, ce.Expression); 26 | 27 | ApplyParameters(animation, ce.Parameters); 28 | return animation; 29 | } 30 | 31 | internal static string ExpressionToPropertyName(Expression expression) 32 | { 33 | var property = ((expression as LambdaExpression)?.Body as MemberExpression)?.Member.Name; 34 | if (property == null) 35 | throw new ArgumentException(); 36 | else 37 | return property; 38 | } 39 | 40 | internal static CompositionAnimation ApplyParameters(CompositionAnimation animation, CompositionAnimationPropertyCollection parameters) 41 | { 42 | foreach (var p in parameters.Keys.ToList()) 43 | { 44 | var type = parameters[p].GetType(); 45 | 46 | if (type == typeof(float)) 47 | animation.SetScalarParameter(p, (float)parameters[p]); 48 | else if (parameters[p] is CompositionObject) 49 | animation.SetReferenceParameter(p, (CompositionObject)parameters[p]); 50 | else if (parameters[p] is CompositionPropertySetWrapper) 51 | { 52 | parameters[p] = ((CompositionPropertySetWrapper)parameters[p]).PropertySet; 53 | animation.SetReferenceParameter(p, (CompositionObject)parameters[p]); 54 | } 55 | else if (type == typeof(Vector2)) 56 | animation.SetVector2Parameter(p, (Vector2)parameters[p]); 57 | else if (type == typeof(Vector3)) 58 | animation.SetVector3Parameter(p, (Vector3)parameters[p]); 59 | else if (type == typeof(Vector4)) 60 | animation.SetVector4Parameter(p, (Vector4)parameters[p]); 61 | else if (type == typeof(Matrix3x2)) 62 | animation.SetMatrix3x2Parameter(p, (Matrix3x2)parameters[p]); 63 | else if (type == typeof(Matrix4x4)) 64 | animation.SetMatrix4x4Parameter(p, (Matrix4x4)parameters[p]); 65 | else if (type == typeof(Quaternion)) 66 | animation.SetQuaternionParameter(p, (Quaternion)parameters[p]); 67 | else if (type == typeof(Color)) 68 | animation.SetColorParameter(p, (Color)parameters[p]); 69 | else 70 | { 71 | parameters[p] = CompositionPropertySetExtensions.ToPropertySet(parameters[p], animation.Compositor); 72 | animation.SetReferenceParameter(p, (CompositionObject)parameters[p]); 73 | } 74 | 75 | } 76 | return animation; 77 | } 78 | 79 | internal static CompositionExpression ExpressionToCompositionExpression(Expression expression) 80 | { 81 | var parameters = new CompositionAnimationPropertyCollection(); 82 | return new CompositionExpression { Expression = GetCompositionString(expression, parameters), Parameters = parameters }; 83 | } 84 | 85 | static string GetMemberExpression(MemberExpression m, CompositionAnimationPropertyCollection parameters) 86 | { 87 | if (m.Expression is MemberExpression) 88 | return GetMemberExpression((MemberExpression)m.Expression, parameters) + "." + m.Member.Name; 89 | else 90 | { 91 | if (m.Member.DeclaringType.GetTypeInfo().IsGenericType && m.Member.DeclaringType.GetGenericTypeDefinition() == typeof(ExpressionContext<,>)) 92 | { 93 | return "this." + m.Member.Name; 94 | } 95 | else 96 | { 97 | if (!parameters.ContainsKey(m.Member.Name) && m.Member is FieldInfo && m.Expression is ConstantExpression) 98 | parameters.Add(m.Member.Name, ((FieldInfo)m.Member).GetValue(((ConstantExpression)m.Expression).Value)); 99 | return m.Member.Name; 100 | } 101 | } 102 | } 103 | 104 | static string GetBinaryExpression(BinaryExpression b, CompositionAnimationPropertyCollection parameters) 105 | { 106 | string operand = null; 107 | 108 | switch (b.NodeType) 109 | { 110 | case ExpressionType.Add: 111 | operand = "+"; 112 | break; 113 | case ExpressionType.AddChecked: 114 | operand = "+"; 115 | break; 116 | case ExpressionType.And: 117 | operand = "&"; 118 | break; 119 | case ExpressionType.AndAlso: 120 | operand = "&&"; 121 | break; 122 | case ExpressionType.Coalesce: 123 | operand = "??"; 124 | break; 125 | case ExpressionType.Divide: 126 | operand = "/"; 127 | break; 128 | case ExpressionType.ExclusiveOr: 129 | operand = "||"; 130 | break; 131 | case ExpressionType.GreaterThan: 132 | operand = ">"; 133 | break; 134 | case ExpressionType.GreaterThanOrEqual: 135 | operand = ">="; 136 | break; 137 | case ExpressionType.LeftShift: 138 | operand = ">>"; 139 | break; 140 | case ExpressionType.LessThan: 141 | operand = "<"; 142 | break; 143 | case ExpressionType.LessThanOrEqual: 144 | operand = "<="; 145 | break; 146 | case ExpressionType.Modulo: 147 | operand = "%"; 148 | break; 149 | case ExpressionType.Multiply: 150 | operand = "*"; 151 | break; 152 | case ExpressionType.MultiplyChecked: 153 | operand = "*"; 154 | break; 155 | case ExpressionType.NotEqual: 156 | operand = "!="; 157 | break; 158 | case ExpressionType.Or: 159 | operand = "|"; 160 | break; 161 | case ExpressionType.OrElse: 162 | operand = "||"; 163 | break; 164 | case ExpressionType.RightShift: 165 | operand = "<<"; 166 | break; 167 | case ExpressionType.Subtract: 168 | operand = "-"; 169 | break; 170 | case ExpressionType.SubtractChecked: 171 | operand = "-"; 172 | break; 173 | case ExpressionType.AddAssign: 174 | operand = "+="; 175 | break; 176 | case ExpressionType.AndAssign: 177 | operand = "&="; 178 | break; 179 | case ExpressionType.DivideAssign: 180 | operand = "/="; 181 | break; 182 | case ExpressionType.ExclusiveOrAssign: 183 | operand = "^="; 184 | break; 185 | case ExpressionType.LeftShiftAssign: 186 | operand = "<<="; 187 | break; 188 | case ExpressionType.ModuloAssign: 189 | operand = "%="; 190 | break; 191 | case ExpressionType.MultiplyAssign: 192 | operand = "*="; 193 | break; 194 | case ExpressionType.OrAssign: 195 | operand = "|="; 196 | break; 197 | case ExpressionType.PowerAssign: 198 | operand = "^"; 199 | break; 200 | case ExpressionType.RightShiftAssign: 201 | operand = ">>="; 202 | break; 203 | case ExpressionType.SubtractAssign: 204 | operand = "-="; 205 | break; 206 | case ExpressionType.AddAssignChecked: 207 | operand = "+="; 208 | break; 209 | case ExpressionType.MultiplyAssignChecked: 210 | operand = "*="; 211 | break; 212 | case ExpressionType.SubtractAssignChecked: 213 | operand = "-="; 214 | break; 215 | default: 216 | throw new ArgumentException(); 217 | } 218 | 219 | return GetExpressionWithParameters(b.Left, parameters) + " " + operand + " " + GetExpressionWithParameters(b.Right, parameters); 220 | } 221 | 222 | static string GetUnaryExpression(UnaryExpression u, CompositionAnimationPropertyCollection parameters) 223 | { 224 | string operand = null; 225 | 226 | switch (u.NodeType) 227 | { 228 | case ExpressionType.Negate: 229 | operand = "!"; 230 | break; 231 | case ExpressionType.UnaryPlus: 232 | operand = "+"; 233 | break; 234 | case ExpressionType.NegateChecked: 235 | operand = "!"; 236 | break; 237 | case ExpressionType.Not: 238 | operand = "!"; 239 | break; 240 | case ExpressionType.PreIncrementAssign: 241 | operand = "++"; 242 | break; 243 | case ExpressionType.PreDecrementAssign: 244 | operand = "--"; 245 | break; 246 | case ExpressionType.Convert: 247 | return GetCompositionString(u.Operand, parameters); 248 | case ExpressionType.PostIncrementAssign: 249 | return GetExpressionWithParameters(u.Operand, parameters) + "++"; 250 | case ExpressionType.PostDecrementAssign: 251 | return GetExpressionWithParameters(u.Operand, parameters) + "--"; 252 | case ExpressionType.OnesComplement: 253 | operand = "~"; 254 | break; 255 | default: 256 | throw new ArgumentException(u.NodeType.ToString()); 257 | } 258 | 259 | return operand + GetExpressionWithParameters(u.Operand, parameters); 260 | } 261 | 262 | static string GetExpressionWithParameters(Expression exp, CompositionAnimationPropertyCollection parameters) 263 | { 264 | if (exp is BinaryExpression) 265 | return "(" + GetCompositionString(exp, parameters) + ")"; 266 | else 267 | return GetCompositionString(exp, parameters); 268 | } 269 | 270 | static string GetConditionalExpression(ConditionalExpression exp, CompositionAnimationPropertyCollection parameters) => GetCompositionString(exp.Test, parameters) + " ? " + GetCompositionString(exp.IfTrue, parameters) + " : " + GetCompositionString(exp.IfFalse, parameters); 271 | 272 | static string GetMethodCallExpression(MethodCallExpression ca, CompositionAnimationPropertyCollection parameters) 273 | { 274 | if (ca.Method.DeclaringType != typeof(CompositionPropertySetExtensions)) 275 | return ca.Method.Name + "(" + string.Join(",", ca.Arguments.Select(a => GetCompositionString(a, parameters))) + ")"; 276 | else 277 | return GetCompositionString(ca.Arguments[0], parameters) + "." + GetCompositionString(ca.Arguments[1], parameters); 278 | } 279 | 280 | static string GetCompositionString(Expression exp, CompositionAnimationPropertyCollection parameters) 281 | { 282 | 283 | if (exp is BinaryExpression) 284 | return GetBinaryExpression((BinaryExpression)exp, parameters); 285 | 286 | if (exp is UnaryExpression) 287 | return GetUnaryExpression((UnaryExpression)exp, parameters); 288 | 289 | switch (exp.NodeType) 290 | { 291 | case ExpressionType.Call: 292 | return GetMethodCallExpression((MethodCallExpression)exp, parameters); 293 | case ExpressionType.Conditional: 294 | return GetConditionalExpression((ConditionalExpression)exp, parameters); 295 | case ExpressionType.Constant: 296 | return (exp as ConstantExpression).Value.ToString(); 297 | case ExpressionType.Lambda: 298 | return GetCompositionString(((System.Linq.Expressions.LambdaExpression)exp).Body, parameters); 299 | case ExpressionType.MemberAccess: 300 | return GetMemberExpression((MemberExpression)exp, parameters); 301 | case ExpressionType.Parameter: 302 | var p = (ParameterExpression)exp; 303 | return p.Name; 304 | default: 305 | throw new ArgumentException(exp.NodeType.ToString()); 306 | } 307 | } 308 | } 309 | } 310 | --------------------------------------------------------------------------------