@@ -10,7 +10,8 @@ public partial class AnimatedImage : Control
1010 private Image _bottomImage ;
1111 private Image _topImage ;
1212 private Compositor _compositor ;
13- private ScalarKeyFrameAnimation ? _opacityAnimation ;
13+ private ScalarKeyFrameAnimation _opacityAnimation ;
14+ private CompositionScopedBatch _currentBatch ;
1415
1516 public Uri ImageUrl
1617 {
@@ -19,101 +20,103 @@ public Uri ImageUrl
1920 }
2021
2122 public static readonly DependencyProperty ImageUrlProperty =
22- DependencyProperty . Register ( nameof ( ImageUrl ) , typeof ( Uri ) , typeof ( AnimatedImage ) , new PropertyMetadata ( null , OnImageSourceChanged ) ) ;
23+ DependencyProperty . Register ( nameof ( ImageUrl ) , typeof ( Uri ) , typeof ( AnimatedImage ) , new PropertyMetadata ( null , OnImageChanged ) ) ;
2324
2425 public BitmapImage ImageSource
2526 {
26- get { return ( BitmapImage ) GetValue ( ImageSourceProperty ) ; }
27- set { SetValue ( ImageSourceProperty , value ) ; }
27+ get => ( BitmapImage ) GetValue ( ImageSourceProperty ) ;
28+ set => SetValue ( ImageSourceProperty , value ) ;
2829 }
2930
3031 public static readonly DependencyProperty ImageSourceProperty =
31- DependencyProperty . Register ( nameof ( ImageSource ) , typeof ( BitmapImage ) , typeof ( AnimatedImage ) , new PropertyMetadata ( null , OnImageSourceChanged ) ) ;
32+ DependencyProperty . Register ( nameof ( ImageSource ) , typeof ( BitmapImage ) , typeof ( AnimatedImage ) , new PropertyMetadata ( null , OnImageChanged ) ) ;
3233
3334 public Stretch Stretch
3435 {
35- get { return ( Stretch ) GetValue ( StretchProperty ) ; }
36- set { SetValue ( StretchProperty , value ) ; }
36+ get => ( Stretch ) GetValue ( StretchProperty ) ;
37+ set => SetValue ( StretchProperty , value ) ;
3738 }
3839
3940 public static readonly DependencyProperty StretchProperty =
4041 DependencyProperty . Register ( nameof ( Stretch ) , typeof ( Stretch ) , typeof ( AnimatedImage ) , new PropertyMetadata ( Stretch . UniformToFill ) ) ;
4142
43+ public TimeSpan OpacityAnimationDuration
44+ {
45+ get { return ( TimeSpan ) GetValue ( OpacityAnimationDurationProperty ) ; }
46+ set { SetValue ( OpacityAnimationDurationProperty , value ) ; }
47+ }
48+
49+ public static readonly DependencyProperty OpacityAnimationDurationProperty =
50+ DependencyProperty . Register ( nameof ( OpacityAnimationDuration ) , typeof ( TimeSpan ) , typeof ( AnimatedImage ) , new PropertyMetadata ( TimeSpan . FromMilliseconds ( 600 ) ) ) ;
51+
4252 public AnimatedImage ( )
4353 {
44- this . DefaultStyleKey = typeof ( AnimatedImage ) ;
54+ DefaultStyleKey = typeof ( AnimatedImage ) ;
4555 }
4656
4757 protected override void OnApplyTemplate ( )
4858 {
4959 base . OnApplyTemplate ( ) ;
5060
51- _compositor = ElementCompositionPreview . GetElementVisual ( this ) . Compositor ;
52-
5361 _bottomImage = GetTemplateChild ( PART_BottomImage ) as Image ;
5462 _topImage = GetTemplateChild ( PART_TopImage ) as Image ;
5563
56- InitAnimations ( ) ;
64+ if ( _bottomImage == null || _topImage == null )
65+ return ;
5766
58- OnIsImageChanged ( ) ;
67+ _compositor = ElementCompositionPreview . GetElementVisual ( this ) . Compositor ;
68+
69+ InitAnimation ( ) ;
70+ UpdateImage ( ) ;
5971 }
60- private static void OnImageSourceChanged ( DependencyObject d , DependencyPropertyChangedEventArgs e )
72+
73+ private static void OnImageChanged ( DependencyObject d , DependencyPropertyChangedEventArgs e )
6174 {
62- if ( d is AnimatedImage control )
63- {
64- control . OnIsImageChanged ( ) ;
65- }
75+ ( ( AnimatedImage ) d ) . UpdateImage ( ) ;
6676 }
6777
68- private void InitAnimations ( )
78+ private void InitAnimation ( )
6979 {
7080 _opacityAnimation = _compositor . CreateScalarKeyFrameAnimation ( ) ;
71- _opacityAnimation . InsertKeyFrame ( 0. 0f, 1.0f ) ;
72- _opacityAnimation . InsertKeyFrame ( 1.0f , 0. 0f) ;
73- _opacityAnimation . Duration = TimeSpan . FromMilliseconds ( 800 ) ;
81+ _opacityAnimation . InsertKeyFrame ( 0f , 1f ) ;
82+ _opacityAnimation . InsertKeyFrame ( 1f , 0f ) ;
83+ _opacityAnimation . Duration = OpacityAnimationDuration ;
7484 }
7585
76- private void OnIsImageChanged ( )
86+ private void UpdateImage ( )
7787 {
7888 if ( _bottomImage == null || _topImage == null )
7989 return ;
8090
81- BitmapImage bitmapImage = null ;
91+ ImageSource newSource = ImageSource ;
8292
83- if ( ImageSource != null )
84- {
85- bitmapImage = ImageSource ;
86- }
87- else if ( ImageUrl != null )
88- {
89- bitmapImage = new BitmapImage ( ImageUrl ) ;
90- }
91- else
92- {
93+ if ( newSource == null && ImageUrl != null )
94+ newSource = new BitmapImage ( ImageUrl ) ;
95+
96+ if ( newSource == null )
9397 return ;
94- }
9598
96- _bottomImage . Source = bitmapImage ;
99+ if ( _bottomImage . Source == newSource )
100+ return ;
97101
98- _bottomImage . Opacity = 1 ;
102+ _bottomImage . Source = newSource ;
99103
100104 var topVisual = ElementCompositionPreview . GetElementVisual ( _topImage ) ;
101- topVisual . Opacity = 1.0f ;
105+
106+ _currentBatch ? . Dispose ( ) ;
107+
108+ topVisual . Opacity = 1f ;
109+
110+ _currentBatch = _compositor . CreateScopedBatch ( CompositionBatchTypes . Animation ) ;
102111
103112 topVisual . StartAnimation ( "Opacity" , _opacityAnimation ) ;
104113
105- // Set new image after fade-out
106- _ = Task . Delay ( 800 ) . ContinueWith ( _ =>
114+ _currentBatch . Completed += ( s , e ) =>
107115 {
108- DispatcherQueue . TryEnqueue ( ( ) =>
109- {
110- try
111- {
112- _topImage . Source = bitmapImage ;
113- topVisual . Opacity = 1.0f ;
114- }
115- catch { }
116- } ) ;
117- } ) ;
116+ _topImage . Source = newSource ;
117+ topVisual . Opacity = 1f ;
118+ } ;
119+
120+ _currentBatch . End ( ) ;
118121 }
119122}
0 commit comments