Skip to content

Commit 3487251

Browse files
committed
transitions improvements
1 parent d3400e4 commit 3487251

File tree

8 files changed

+226
-42
lines changed

8 files changed

+226
-42
lines changed

MainDemo.Wpf/TransitionsDemo/Slide5_TransitioningContent.xaml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,91 @@
2222
</StackPanel>
2323
</materialDesign:ColorZone>
2424
</materialDesign:TransitioningContent>
25+
<ItemsControl Grid.Row="1">
26+
<ItemsControl.ItemsPanel>
27+
<ItemsPanelTemplate>
28+
<UniformGrid Columns="4" />
29+
</ItemsPanelTemplate>
30+
</ItemsControl.ItemsPanel>
31+
<ItemsControl.Resources>
32+
<Style TargetType="{x:Type materialDesign:ColorZone}" BasedOn="{StaticResource {x:Type materialDesign:ColorZone}}">
33+
<Setter Property="Width" Value="96" />
34+
<Setter Property="Height" Value="96" />
35+
<Setter Property="Margin" Value="4" />
36+
<Setter Property="Mode" Value="PrimaryLight" />
37+
</Style>
38+
</ItemsControl.Resources>
39+
<materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect ExpandIn}">
40+
<materialDesign:ColorZone>
41+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
42+
</materialDesign:ColorZone>
43+
</materialDesign:TransitioningContent>
44+
45+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
46+
<materialDesign:TransitioningContent.OpeningEffects>
47+
<materialDesign:TransitionEffect Kind="ExpandIn" />
48+
</materialDesign:TransitioningContent.OpeningEffects>
49+
<materialDesign:ColorZone>
50+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
51+
</materialDesign:ColorZone>
52+
</materialDesign:TransitioningContent>
53+
54+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
55+
<materialDesign:TransitioningContent.OpeningEffects>
56+
<materialDesign:TransitionEffect Kind="ExpandIn" />
57+
</materialDesign:TransitioningContent.OpeningEffects>
58+
<materialDesign:ColorZone>
59+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
60+
</materialDesign:ColorZone>
61+
</materialDesign:TransitioningContent>
62+
63+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
64+
<materialDesign:TransitioningContent.OpeningEffects>
65+
<materialDesign:TransitionEffect Kind="ExpandIn" />
66+
</materialDesign:TransitioningContent.OpeningEffects>
67+
<materialDesign:ColorZone>
68+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
69+
</materialDesign:ColorZone>
70+
</materialDesign:TransitioningContent>
71+
72+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
73+
<materialDesign:TransitioningContent.OpeningEffects>
74+
<materialDesign:TransitionEffect Kind="ExpandIn" />
75+
</materialDesign:TransitioningContent.OpeningEffects>
76+
<materialDesign:ColorZone>
77+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
78+
</materialDesign:ColorZone>
79+
</materialDesign:TransitioningContent>
80+
81+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
82+
<materialDesign:TransitioningContent.OpeningEffects>
83+
<materialDesign:TransitionEffect Kind="ExpandIn" />
84+
</materialDesign:TransitioningContent.OpeningEffects>
85+
<materialDesign:ColorZone>
86+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
87+
</materialDesign:ColorZone>
88+
</materialDesign:TransitioningContent>
89+
90+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
91+
<materialDesign:TransitioningContent.OpeningEffects>
92+
<materialDesign:TransitionEffect Kind="ExpandIn" />
93+
</materialDesign:TransitioningContent.OpeningEffects>
94+
<materialDesign:ColorZone>
95+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
96+
</materialDesign:ColorZone>
97+
</materialDesign:TransitioningContent>
98+
99+
<materialDesign:TransitioningContent OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
100+
<materialDesign:TransitioningContent.OpeningEffects>
101+
<materialDesign:TransitionEffect Kind="ExpandIn" />
102+
</materialDesign:TransitioningContent.OpeningEffects>
103+
<materialDesign:ColorZone>
104+
<materialDesign:PackIcon Kind="Phone" VerticalAlignment="Center" HorizontalAlignment="Center" />
105+
</materialDesign:ColorZone>
106+
</materialDesign:TransitioningContent>
107+
108+
</ItemsControl>
109+
<!--
25110
<UniformGrid Grid.Row="1" Columns="4">
26111
<UniformGrid.Resources>
27112
<Style TargetType="{x:Type materialDesign:ColorZone}" BasedOn="{StaticResource {x:Type materialDesign:ColorZone}}">
@@ -102,6 +187,7 @@
102187
</materialDesign:TransitioningContent>
103188
104189
</UniformGrid>
190+
-->
105191
<StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Right">
106192
<Button Style="{DynamicResource MaterialDesignFloatingActionMiniButton}"
107193
Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"

MaterialDesignThemes.Wpf/MaterialDesignThemes.Wpf.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@
257257
<Compile Include="Icon.cs" />
258258
<Compile Include="IconType.cs" />
259259
<Compile Include="Transitions\CircleWipe.cs" />
260+
<Compile Include="Transitions\IndexedItemOffsetMultiplierExtension.cs" />
260261
<Compile Include="Transitions\ITransitionEffect.cs" />
261262
<Compile Include="Transitions\ITransitionEffectSubject.cs" />
262263
<Compile Include="Transitions\ITransitionWipe.cs" />

MaterialDesignThemes.Wpf/Transitions/ITransitionEffectSubject.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
13
namespace MaterialDesignThemes.Wpf.Transitions
24
{
35
public interface ITransitionEffectSubject
@@ -7,5 +9,6 @@ public interface ITransitionEffectSubject
79
string ScaleTransformName { get; }
810
string SkewTransformName { get; }
911
string TranslateTransformName { get; }
12+
TimeSpan Offset { get; }
1013
}
1114
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Controls;
4+
using System.Windows.Markup;
5+
using System.Windows.Media;
6+
7+
namespace MaterialDesignThemes.Wpf.Transitions
8+
{
9+
/// <summary>
10+
/// Multiplies a time span unit by the index of an item in a list.
11+
/// </summary>
12+
/// <remarks>
13+
/// Example usage is for a <see cref="TransitioningContent"/> to have a <see cref="TransitionEffect.OffsetTime" />
14+
/// time delayed according to position in a list, so cascading animations can occur.
15+
/// </remarks>
16+
[MarkupExtensionReturnType(typeof(TimeSpan))]
17+
public class IndexedItemOffsetMultiplierExtension : MarkupExtension
18+
{
19+
public IndexedItemOffsetMultiplierExtension(TimeSpan unit)
20+
{
21+
Unit = unit;
22+
}
23+
24+
[ConstructorArgument("unit")]
25+
public TimeSpan Unit { get; set; }
26+
27+
public override object ProvideValue(IServiceProvider serviceProvider)
28+
{
29+
var provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
30+
if (provideValueTarget == null) return TimeSpan.Zero;
31+
32+
if (provideValueTarget.TargetObject != null &&
33+
provideValueTarget.TargetObject.GetType().FullName == "System.Windows.SharedDp")
34+
//we are inside a template, return this, so we can re-evaluate later...
35+
return this;
36+
37+
var element = provideValueTarget?.TargetObject as DependencyObject;
38+
if (element == null) return TimeSpan.Zero;
39+
40+
var itemsControl = ItemsControl.ItemsControlFromItemContainer(element);
41+
if (itemsControl == null)
42+
{
43+
var ancestor = element;
44+
while (ancestor != null && itemsControl == null)
45+
{
46+
ancestor = VisualTreeHelper.GetParent(ancestor);
47+
itemsControl = ItemsControl.ItemsControlFromItemContainer(ancestor);
48+
}
49+
}
50+
if (itemsControl == null) return TimeSpan.Zero;
51+
52+
var isOwnContainer = itemsControl.IsItemItsOwnContainer(element);
53+
var container = isOwnContainer
54+
? element
55+
: itemsControl.ItemContainerGenerator.ContainerFromItem(element);
56+
if (container == null)
57+
{
58+
var dataContext = (element as FrameworkElement)?.DataContext;
59+
if (dataContext != null)
60+
container = itemsControl.ItemContainerGenerator.ContainerFromItem(dataContext);
61+
}
62+
63+
if (container == null) return TimeSpan.Zero;
64+
65+
var multiplier = itemsControl.ItemContainerGenerator.IndexFromContainer(container);
66+
if (multiplier == -1) //container generation may not have completed
67+
{
68+
multiplier = itemsControl.Items.IndexOf(element);
69+
}
70+
71+
return multiplier > -1 ? new TimeSpan(Unit.Ticks * multiplier) : TimeSpan.Zero;
72+
}
73+
}
74+
}

MaterialDesignThemes.Wpf/Transitions/TransitionEffect.cs

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,51 +44,55 @@ public override Timeline Build<TSubject>(TSubject effectSubject)
4444
case TransitionEffectKind.ExpandIn:
4545
return CreateExpandIn(effectSubject);
4646
case TransitionEffectKind.SlideInFromLeft:
47-
timeline = CreateSlide(-300, 0);
47+
timeline = CreateSlide(-300, 0, effectSubject.Offset);
4848
property = TranslateTransform.XProperty;
4949
targetName = effectSubject.TranslateTransformName;
5050
break;
5151
case TransitionEffectKind.SlideInFromTop:
52-
timeline = CreateSlide(-300, 0);
52+
timeline = CreateSlide(-300, 0, effectSubject.Offset);
5353
property = TranslateTransform.YProperty;
5454
targetName = effectSubject.TranslateTransformName;
5555
break;
5656
case TransitionEffectKind.SlideInFromRight:
57-
timeline = CreateSlide(300, 0);
57+
timeline = CreateSlide(300, 0, effectSubject.Offset);
5858
property = TranslateTransform.XProperty;
5959
targetName = effectSubject.TranslateTransformName;
6060
break;
6161
case TransitionEffectKind.SlideInFromBottom:
62-
timeline = CreateSlide(300, 0);
62+
timeline = CreateSlide(300, 0, effectSubject.Offset);
6363
property = TranslateTransform.YProperty;
6464
targetName = effectSubject.TranslateTransformName;
6565
break;
6666
case TransitionEffectKind.FadeIn:
67-
timeline = new DoubleAnimation { EasingFunction = new SineEase(), From = 0, To = 1};
67+
timeline = CreateFadeIn(effectSubject.Offset);
6868
property = OpacityProperty;
6969
target = effectSubject;
7070
break;
7171
default:
7272
throw new ArgumentOutOfRangeException();
7373
}
7474

75-
if (timeline == null || (target == null && targetName == null)) return null;
76-
timeline.Duration = Duration;
75+
if (timeline == null || (target == null && targetName == null)) return null;
76+
timeline.Duration = Duration + effectSubject.Offset;
7777
if (target != null)
7878
Storyboard.SetTarget(timeline, target);
7979
if (targetName != null)
80-
Storyboard.SetTargetName(timeline, targetName);
81-
80+
Storyboard.SetTargetName(timeline, targetName);
81+
8282
Storyboard.SetTargetProperty(timeline, new PropertyPath(property));
8383

8484
return timeline;
8585
}
86+
private Timeline CreateFadeIn(TimeSpan initialOffset)
87+
{
88+
return CreateSlide(0, 1, initialOffset);
89+
}
8690

87-
private Timeline CreateSlide(double from, double to)
91+
private Timeline CreateSlide(double from, double to, TimeSpan initialOffset)
8892
{
8993
var zeroFrame = new DiscreteDoubleKeyFrame(from);
90-
var startFrame = new DiscreteDoubleKeyFrame(from, OffsetTime);
91-
var endFrame = new EasingDoubleKeyFrame(to, OffsetTime + Duration) { EasingFunction = new SineEase() };
94+
var startFrame = new DiscreteDoubleKeyFrame(from, initialOffset + OffsetTime);
95+
var endFrame = new EasingDoubleKeyFrame(to, initialOffset + OffsetTime + Duration) { EasingFunction = new SineEase() };
9296
var slideAnimation = new DoubleAnimationUsingKeyFrames();
9397
slideAnimation.KeyFrames.Add(zeroFrame);
9498
slideAnimation.KeyFrames.Add(startFrame);
@@ -101,8 +105,8 @@ private Timeline CreateExpandIn(ITransitionEffectSubject effectSubject)
101105
{
102106
var scaleXAnimation = new DoubleAnimationUsingKeyFrames();
103107
var zeroFrame = new DiscreteDoubleKeyFrame(0.0);
104-
var startFrame = new DiscreteDoubleKeyFrame(.5, OffsetTime);
105-
var endFrame = new EasingDoubleKeyFrame(1, OffsetTime + Duration) { EasingFunction = new SineEase() };
108+
var startFrame = new DiscreteDoubleKeyFrame(.5, effectSubject.Offset + OffsetTime);
109+
var endFrame = new EasingDoubleKeyFrame(1, effectSubject.Offset + OffsetTime + Duration) { EasingFunction = new SineEase() };
106110
scaleXAnimation.KeyFrames.Add(zeroFrame);
107111
scaleXAnimation.KeyFrames.Add(startFrame);
108112
scaleXAnimation.KeyFrames.Add(endFrame);
@@ -119,30 +123,7 @@ private Timeline CreateExpandIn(ITransitionEffectSubject effectSubject)
119123
parallelTimeline.Children.Add(scaleXAnimation);
120124
parallelTimeline.Children.Add(scaleYAnimation);
121125

122-
return parallelTimeline;
123-
124-
/*
125-
var scaleXAnimation = new DoubleAnimation { EasingFunction = new SineEase(), From = .5, To = 1 };
126-
scaleXAnimation.BeginTime = BeginTime;
127-
scaleXAnimation.Duration = Duration;
128-
129-
130-
Storyboard.SetTargetName(scaleXAnimation, effectSubject.ScaleTransformName);
131-
Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath(ScaleTransform.ScaleXProperty));
132-
133-
var scaleYAnimation = new DoubleAnimation { EasingFunction = new SineEase(), From = .5, To = 1 };
134-
scaleYAnimation.BeginTime = BeginTime;
135-
scaleYAnimation.Duration = Duration;
136-
Storyboard.SetTargetName(scaleYAnimation, effectSubject.ScaleTransformName);
137-
Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath(ScaleTransform.ScaleYProperty.Name));
138-
139-
var parallelTimeline = new ParallelTimeline();
140-
parallelTimeline.Children.Add(scaleXAnimation);
141-
parallelTimeline.Children.Add(scaleYAnimation);
142-
143-
return parallelTimeline;
144-
145-
*/
126+
return parallelTimeline;
146127
}
147128
}
148129
}

MaterialDesignThemes.Wpf/Transitions/TransitionEffectExtension.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Windows;
32
using System.Windows.Markup;
43

54
namespace MaterialDesignThemes.Wpf.Transitions

MaterialDesignThemes.Wpf/Transitions/TransitioningContent.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
using System.Windows;
1+
using System;
2+
using System.Windows;
23

34
namespace MaterialDesignThemes.Wpf.Transitions
45
{
6+
[Flags]
7+
public enum TransitioningContentRunHint
8+
{
9+
Loaded = 1,
10+
IsVisibleChanged = 2,
11+
All = Loaded | IsVisibleChanged
12+
}
13+
14+
515
/// <summary>
616
/// Content control to enable easier transitions.
717
/// </summary>
@@ -14,8 +24,23 @@ static TransitioningContent()
1424

1525
public TransitioningContent()
1626
{
17-
Loaded += (sender, args) => RunOpeningEffects();
18-
IsVisibleChanged += (sender, args) => RunOpeningEffects();
27+
Loaded += (sender, args) => Run(TransitioningContentRunHint.Loaded);
28+
IsVisibleChanged += (sender, args) => Run(TransitioningContentRunHint.IsVisibleChanged);
29+
}
30+
31+
public static readonly DependencyProperty RunHintProperty = DependencyProperty.Register(
32+
"RunHint", typeof(TransitioningContentRunHint), typeof(TransitioningContent), new PropertyMetadata(TransitioningContentRunHint.All));
33+
34+
public TransitioningContentRunHint RunHint
35+
{
36+
get { return (TransitioningContentRunHint)GetValue(RunHintProperty); }
37+
set { SetValue(RunHintProperty, value); }
38+
}
39+
40+
private void Run(TransitioningContentRunHint requiredHint)
41+
{
42+
if ((RunHint & requiredHint) == requiredHint)
43+
RunOpeningEffects();
1944
}
2045
}
2146
}

MaterialDesignThemes.Wpf/Transitions/TransitioningContentBase.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.ObjectModel;
23
using System.ComponentModel;
34
using System.Linq;
@@ -75,6 +76,18 @@ public TransitionEffectBase OpeningEffect
7576
set { SetValue(OpeningEffectProperty, value); }
7677
}
7778

79+
public static readonly DependencyProperty OpeningEffectsOffsetProperty = DependencyProperty.Register(
80+
"OpeningEffectsOffset", typeof (TimeSpan), typeof (TransitioningContentBase), new PropertyMetadata(default(TimeSpan)));
81+
82+
/// <summary>
83+
/// Delay offset to be applied to all opening effect transitions.
84+
/// </summary>
85+
public TimeSpan OpeningEffectsOffset
86+
{
87+
get { return (TimeSpan) GetValue(OpeningEffectsOffsetProperty); }
88+
set { SetValue(OpeningEffectsOffsetProperty, value); }
89+
}
90+
7891
/// <summary>
7992
/// Allows multiple transition effects to be combined and run upon the content loading or being made visible.
8093
/// </summary>
@@ -90,6 +103,8 @@ public TransitionEffectBase OpeningEffect
90103

91104
string ITransitionEffectSubject.TranslateTransformName => TranslateTransformPartName;
92105

106+
TimeSpan ITransitionEffectSubject.Offset => OpeningEffectsOffset;
107+
93108
protected virtual void RunOpeningEffects()
94109
{
95110
if (!IsLoaded) return;

0 commit comments

Comments
 (0)