@@ -148,16 +148,7 @@ protected override void WriteImplementationFileStart(CodeBuilder builder)
148148 // Write a description of the source as comments.
149149 builder . WritePreformattedCommentLines ( GetSourceDescriptionLines ( ) ) ;
150150
151- // If the composition has LoadedImageSurface, write a class that implements the IDynamicAnimatedVisualSource interface.
152- // Otherwise, implement the IAnimatedVisualSource interface.
153- if ( SourceInfo . LoadedImageSurfaces . Count > 0 )
154- {
155- WriteIDynamicAnimatedVisualSource ( builder ) ;
156- }
157- else
158- {
159- WriteIAnimatedVisualSource ( builder ) ;
160- }
151+ WriteIAnimatedVisualSource ( builder , SourceInfo . LoadedImageSurfaces . Count > 0 ) ;
161152
162153 builder . WriteLine ( ) ;
163154
@@ -263,9 +254,9 @@ void WriteDependencyPropertyChangeHandlers(CodeBuilder builder)
263254 }
264255
265256 /// <summary>
266- /// Writes a class that implements the IAnimatedVisualSource interface .
257+ /// Writes a class that implements IAnimatedVisualSourceX interfaces or optional IDynamicAnimatedVisualSource .
267258 /// </summary>
268- void WriteIAnimatedVisualSource ( CodeBuilder builder )
259+ void WriteIAnimatedVisualSource ( CodeBuilder builder , bool implementDynamicAVS )
269260 {
270261 var visibility = SourceInfo . Public ? "public " : string . Empty ;
271262
@@ -287,6 +278,12 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
287278 builder . WriteLine ( $ ", { Interface_IAnimatedVisualSource2 . GetQualifiedName ( _s ) } ") ;
288279 }
289280
281+ if ( implementDynamicAVS )
282+ {
283+ builder . WriteLine ( $ ", { Interface_IDynamicAnimatedVisualSource . GetQualifiedName ( _s ) } ") ;
284+ builder . WriteLine ( ", INotifyPropertyChanged" ) ;
285+ }
286+
290287 foreach ( var additionalInterface in SourceInfo . AdditionalInterfaces )
291288 {
292289 builder . WriteLine ( $ ", { additionalInterface . GetQualifiedName ( _s ) } ") ;
@@ -296,6 +293,33 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
296293
297294 builder . OpenScope ( ) ;
298295
296+ if ( implementDynamicAVS )
297+ {
298+ // Declare variables.
299+ builder . WriteLine ( $ "const int c_loadedImageSurfaceCount = { SourceInfo . LoadedImageSurfaces . Count } ;") ;
300+ builder . WriteLine ( $ "int _loadCompleteEventCount;") ;
301+ builder . WriteLine ( "bool _isImageLoadingAsynchronous;" ) ;
302+ builder . WriteLine ( "bool _isTryCreateAnimatedVisualCalled;" ) ;
303+ builder . WriteLine ( "bool _isImageLoadingStarted;" ) ;
304+
305+ if ( AnimatedVisualSourceInfo . WinUIVersion . Major >= 3 )
306+ {
307+ builder . WriteLine ( "HashSet<TypedEventHandler<IDynamicAnimatedVisualSource, object>> _animatedVisualInvalidatedEventTokenTable = new HashSet<TypedEventHandler<IDynamicAnimatedVisualSource, object>>();" ) ;
308+ }
309+ else
310+ {
311+ builder . WriteLine ( "EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> _animatedVisualInvalidatedEventTokenTable;" ) ;
312+ }
313+
314+ // Declare the variables to hold the LoadedImageSurfaces.
315+ foreach ( var n in SourceInfo . LoadedImageSurfaces )
316+ {
317+ builder . WriteLine ( $ "{ _s . ReferenceTypeName ( n . TypeName ) } { n . FieldName } ;") ;
318+ }
319+
320+ builder . WriteLine ( ) ;
321+ }
322+
299323 // Add any internal constants.
300324 foreach ( var c in SourceInfo . InternalConstants )
301325 {
@@ -322,6 +346,39 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
322346 // Add the methods and fields needed for theming.
323347 WriteThemeMethodsAndFields ( builder ) ;
324348
349+ if ( implementDynamicAVS )
350+ {
351+ // Implement the INotifyPropertyChanged.PropertyChanged event.
352+ builder . WriteSummaryComment ( "This implementation of the INotifyPropertyChanged.PropertyChanged event is specific to C# and does not work on WinRT." ) ;
353+ builder . WriteLine ( "public event PropertyChangedEventHandler PropertyChanged;" ) ;
354+ builder . WriteLine ( ) ;
355+
356+ // Implement the AnimatedVisualInvalidated event.
357+ WriteAnimatedVisualInvalidatedEvent ( builder ) ;
358+
359+ // Define properties.
360+ builder . WriteSummaryComment ( "If this property is set to true, <see cref=\" TryCreateAnimatedVisual\" /> will return null" +
361+ " until all images have loaded. When all images have loaded, <see cref=\" TryCreateAnimatedVisual\" /> will return" +
362+ " the AnimatedVisual. To use, set it when instantiating the AnimatedVisualSource. Once <see cref=\" TryCreateAnimatedVisual\" />" +
363+ " is called, changes made to this property will be ignored. Default value is false." ) ;
364+ builder . WriteLine ( "public bool IsImageLoadingAsynchronous" ) ;
365+ builder . OpenScope ( ) ;
366+ builder . WriteLine ( "get { return _isImageLoadingAsynchronous; }" ) ;
367+ builder . WriteLine ( "set" ) ;
368+ builder . OpenScope ( ) ;
369+ builder . WriteLine ( "if (!_isTryCreateAnimatedVisualCalled && _isImageLoadingAsynchronous != value)" ) ;
370+ builder . OpenScope ( ) ;
371+ builder . WriteLine ( "_isImageLoadingAsynchronous = value;" ) ;
372+ builder . WriteLine ( "NotifyPropertyChanged(nameof(IsImageLoadingAsynchronous));" ) ;
373+ builder . CloseScope ( ) ;
374+ builder . CloseScope ( ) ;
375+ builder . CloseScope ( ) ;
376+ builder . WriteLine ( ) ;
377+ builder . WriteSummaryComment ( "Returns true if all images have finished loading." ) ;
378+ builder . WriteLine ( "public bool IsImageLoadingCompleted { get; private set; }" ) ;
379+ builder . WriteLine ( ) ;
380+ }
381+
325382 // Generate the overload of TryCreateAnimatedVisual that doesn't return diagnostics.
326383 builder . WriteLine ( $ "public { Interface_IAnimatedVisual . GetQualifiedName ( _s ) } TryCreateAnimatedVisual(Compositor compositor)") ;
327384 builder . OpenScope ( ) ;
@@ -333,6 +390,11 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
333390 // Generate the method that creates an instance of the animated visual.
334391 builder . WriteLine ( $ "public { Interface_IAnimatedVisual . GetQualifiedName ( _s ) } TryCreateAnimatedVisual(Compositor compositor, out object diagnostics)") ;
335392 builder . OpenScope ( ) ;
393+ if ( implementDynamicAVS )
394+ {
395+ builder . WriteLine ( "_isTryCreateAnimatedVisualCalled = true;" ) ;
396+ }
397+
336398 builder . WriteLine ( "diagnostics = null;" ) ;
337399 if ( SourceInfo . IsThemed )
338400 {
@@ -341,6 +403,31 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
341403
342404 builder . WriteLine ( ) ;
343405
406+ var animatedVisualInfos = SourceInfo . AnimatedVisualInfos . OrderByDescending ( avi => avi . RequiredUapVersion ) . ToArray ( ) ;
407+
408+ if ( implementDynamicAVS )
409+ {
410+ // WinUI3 doesn't ever do a version check. It's up to the user to make sure
411+ // the version they're using is compatible.
412+ if ( SourceInfo . WinUIVersion . Major < 3 )
413+ {
414+ // Check whether the runtime will support the lowest UAP version required.
415+ builder . WriteLine ( $ "if (!{ animatedVisualInfos [ ^ 1 ] . ClassName } .IsRuntimeCompatible())") ;
416+ builder . OpenScope ( ) ;
417+ builder . WriteLine ( "return null;" ) ;
418+ builder . CloseScope ( ) ;
419+ builder . WriteLine ( ) ;
420+ }
421+
422+ builder . WriteLine ( "EnsureImageLoadingStarted();" ) ;
423+ builder . WriteLine ( ) ;
424+ builder . WriteLine ( "if (_isImageLoadingAsynchronous && _loadCompleteEventCount != c_loadedImageSurfaceCount)" ) ;
425+ builder . OpenScope ( ) ;
426+ builder . WriteLine ( "return null;" ) ;
427+ builder . CloseScope ( ) ;
428+ builder . WriteLine ( ) ;
429+ }
430+
344431 // WinUI3 doesn't ever do a version check. It's up to the user to make sure
345432 // the version they're using is compatible.
346433 if ( SourceInfo . WinUIVersion . Major >= 3 )
@@ -350,7 +437,6 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
350437 else
351438 {
352439 // Check the runtime version and instantiate the highest compatible IAnimatedVisual class.
353- var animatedVisualInfos = SourceInfo . AnimatedVisualInfos . OrderByDescending ( avi => avi . RequiredUapVersion ) . ToArray ( ) ;
354440 for ( var i = 0 ; i < animatedVisualInfos . Length ; i ++ )
355441 {
356442 var current = animatedVisualInfos [ i ] ;
@@ -365,6 +451,31 @@ void WriteIAnimatedVisualSource(CodeBuilder builder)
365451 }
366452
367453 builder . CloseScope ( ) ;
454+
455+ if ( implementDynamicAVS )
456+ {
457+ // Generate the method that load all the LoadedImageSurfaces.
458+ WriteEnsureImageLoadingStarted ( builder ) ;
459+
460+ // Generate the method that handle the LoadCompleted event of the LoadedImageSurface objects.
461+ WriteHandleLoadCompleted ( builder ) ;
462+
463+ // Generate the method that raise the PropertyChanged event.
464+ builder . WriteLine ( "void NotifyPropertyChanged(string name)" ) ;
465+ builder . OpenScope ( ) ;
466+ builder . WriteLine ( "PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));" ) ;
467+ builder . CloseScope ( ) ;
468+ builder . WriteLine ( ) ;
469+
470+ // Generate the method that get or create the EventRegistrationTokenTable.
471+ if ( AnimatedVisualSourceInfo . WinUIVersion . Major < 3 )
472+ {
473+ builder . WriteLine ( "EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> GetAnimatedVisualInvalidatedEventRegistrationTokenTable()" ) ;
474+ builder . OpenScope ( ) ;
475+ builder . WriteLine ( "return EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>>.GetOrCreateEventRegistrationTokenTable(ref _animatedVisualInvalidatedEventTokenTable);" ) ;
476+ builder . CloseScope ( ) ;
477+ }
478+ }
368479 }
369480
370481 void WriteThemeMethodsAndFields ( CodeBuilder builder )
@@ -440,172 +551,6 @@ string GetDefaultPropertyBindingValue(PropertyBinding prop)
440551 _ => throw new InvalidOperationException ( ) ,
441552 } ;
442553
443- /// <summary>
444- /// Write a class that implements the IDynamicAnimatedVisualSource interface.
445- /// </summary>
446- void WriteIDynamicAnimatedVisualSource ( CodeBuilder builder )
447- {
448- var visibility = SourceInfo . Public ? "public " : string . Empty ;
449-
450- builder . WriteLine ( $ "{ visibility } sealed class { SourceInfo . ClassName } ") ;
451-
452- if ( SourceInfo . GenerateDependencyObject )
453- {
454- builder . WriteLine ( $ " : DependencyObject") ;
455- builder . WriteLine ( " , IDynamicAnimatedVisualSource" ) ;
456- }
457- else
458- {
459- builder . WriteLine ( " : IDynamicAnimatedVisualSource" ) ;
460- }
461-
462- foreach ( var additionalInterface in SourceInfo . AdditionalInterfaces )
463- {
464- builder . WriteLine ( $ " , { additionalInterface . GetQualifiedName ( _s ) } ") ;
465- }
466-
467- builder . WriteLine ( " , INotifyPropertyChanged" ) ;
468-
469- builder . OpenScope ( ) ;
470-
471- // Declare variables.
472- builder . WriteLine ( $ "const int c_loadedImageSurfaceCount = { SourceInfo . LoadedImageSurfaces . Count } ;") ;
473- builder . WriteLine ( $ "int _loadCompleteEventCount;") ;
474- builder . WriteLine ( "bool _isImageLoadingAsynchronous;" ) ;
475- builder . WriteLine ( "bool _isTryCreateAnimatedVisualCalled;" ) ;
476- builder . WriteLine ( "bool _isImageLoadingStarted;" ) ;
477-
478- if ( AnimatedVisualSourceInfo . WinUIVersion . Major >= 3 )
479- {
480- builder . WriteLine ( "HashSet<TypedEventHandler<IDynamicAnimatedVisualSource, object>> _animatedVisualInvalidatedEventTokenTable = new HashSet<TypedEventHandler<IDynamicAnimatedVisualSource, object>>();" ) ;
481- }
482- else
483- {
484- builder . WriteLine ( "EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> _animatedVisualInvalidatedEventTokenTable;" ) ;
485- }
486-
487- // Declare the variables to hold the LoadedImageSurfaces.
488- foreach ( var n in SourceInfo . LoadedImageSurfaces )
489- {
490- builder . WriteLine ( $ "{ _s . ReferenceTypeName ( n . TypeName ) } { n . FieldName } ;") ;
491- }
492-
493- builder . WriteLine ( ) ;
494-
495- // Add the methods and fields needed for theming.
496- WriteThemeMethodsAndFields ( builder ) ;
497-
498- // Implement the INotifyPropertyChanged.PropertyChanged event.
499- builder . WriteSummaryComment ( "This implementation of the INotifyPropertyChanged.PropertyChanged event is specific to C# and does not work on WinRT." ) ;
500- builder . WriteLine ( "public event PropertyChangedEventHandler PropertyChanged;" ) ;
501- builder . WriteLine ( ) ;
502-
503- // Implement the AnimatedVisualInvalidated event.
504- WriteAnimatedVisualInvalidatedEvent ( builder ) ;
505-
506- // Define properties.
507- builder . WriteSummaryComment ( "If this property is set to true, <see cref=\" TryCreateAnimatedVisual\" /> will return null" +
508- " until all images have loaded. When all images have loaded, <see cref=\" TryCreateAnimatedVisual\" /> will return" +
509- " the AnimatedVisual. To use, set it when instantiating the AnimatedVisualSource. Once <see cref=\" TryCreateAnimatedVisual\" />" +
510- " is called, changes made to this property will be ignored. Default value is false." ) ;
511- builder . WriteLine ( "public bool IsImageLoadingAsynchronous" ) ;
512- builder . OpenScope ( ) ;
513- builder . WriteLine ( "get { return _isImageLoadingAsynchronous; }" ) ;
514- builder . WriteLine ( "set" ) ;
515- builder . OpenScope ( ) ;
516- builder . WriteLine ( "if (!_isTryCreateAnimatedVisualCalled && _isImageLoadingAsynchronous != value)" ) ;
517- builder . OpenScope ( ) ;
518- builder . WriteLine ( "_isImageLoadingAsynchronous = value;" ) ;
519- builder . WriteLine ( "NotifyPropertyChanged(nameof(IsImageLoadingAsynchronous));" ) ;
520- builder . CloseScope ( ) ;
521- builder . CloseScope ( ) ;
522- builder . CloseScope ( ) ;
523- builder . WriteLine ( ) ;
524-
525- builder . WriteSummaryComment ( "Returns true if all images have finished loading." ) ;
526- builder . WriteLine ( "public bool IsImageLoadingCompleted { get; private set; }" ) ;
527- builder . WriteLine ( ) ;
528-
529- // Generate the method that creates an instance of the animated visual.
530- builder . WriteLine ( $ "public { Interface_IAnimatedVisual . GetQualifiedName ( _s ) } TryCreateAnimatedVisual(Compositor compositor, out object diagnostics)") ;
531- builder . OpenScope ( ) ;
532- builder . WriteLine ( "_isTryCreateAnimatedVisualCalled = true;" ) ;
533- builder . WriteLine ( "diagnostics = null;" ) ;
534- builder . WriteLine ( ) ;
535-
536- var animatedVisualInfos = SourceInfo . AnimatedVisualInfos . OrderByDescending ( avi => avi . RequiredUapVersion ) . ToArray ( ) ;
537-
538- // WinUI3 doesn't ever do a version check. It's up to the user to make sure
539- // the version they're using is compatible.
540- if ( SourceInfo . WinUIVersion . Major < 3 )
541- {
542- // Check whether the runtime will support the lowest UAP version required.
543- builder . WriteLine ( $ "if (!{ animatedVisualInfos [ ^ 1 ] . ClassName } .IsRuntimeCompatible())") ;
544- builder . OpenScope ( ) ;
545- builder . WriteLine ( "return null;" ) ;
546- builder . CloseScope ( ) ;
547- builder . WriteLine ( ) ;
548- }
549-
550- builder . WriteLine ( "EnsureImageLoadingStarted();" ) ;
551- builder . WriteLine ( ) ;
552- builder . WriteLine ( "if (_isImageLoadingAsynchronous && _loadCompleteEventCount != c_loadedImageSurfaceCount)" ) ;
553- builder . OpenScope ( ) ;
554- builder . WriteLine ( "return null;" ) ;
555- builder . CloseScope ( ) ;
556- builder . WriteLine ( ) ;
557-
558- // Check the runtime version and instantiate the highest compatible IAnimatedVisual class.
559- for ( var i = 0 ; i < animatedVisualInfos . Length ; i ++ )
560- {
561- var current = animatedVisualInfos [ i ] ;
562- var versionTestRequired = i < animatedVisualInfos . Length - 1 ;
563-
564- if ( i > 0 )
565- {
566- builder . WriteLine ( ) ;
567- }
568-
569- if ( versionTestRequired )
570- {
571- builder . WriteLine ( $ "if ({ current . ClassName } .IsRuntimeCompatible())") ;
572- builder . OpenScope ( ) ;
573- }
574-
575- WriteInstantiateAndReturnAnimatedVisual ( builder , current ) ;
576-
577- if ( versionTestRequired )
578- {
579- builder . CloseScope ( ) ;
580- }
581- }
582-
583- builder . CloseScope ( ) ;
584- builder . WriteLine ( ) ;
585-
586- // Generate the method that load all the LoadedImageSurfaces.
587- WriteEnsureImageLoadingStarted ( builder ) ;
588-
589- // Generate the method that handle the LoadCompleted event of the LoadedImageSurface objects.
590- WriteHandleLoadCompleted ( builder ) ;
591-
592- // Generate the method that raise the PropertyChanged event.
593- builder . WriteLine ( "void NotifyPropertyChanged(string name)" ) ;
594- builder . OpenScope ( ) ;
595- builder . WriteLine ( "PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));" ) ;
596- builder . CloseScope ( ) ;
597- builder . WriteLine ( ) ;
598-
599- // Generate the method that get or create the EventRegistrationTokenTable.
600- if ( AnimatedVisualSourceInfo . WinUIVersion . Major < 3 )
601- {
602- builder . WriteLine ( "EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>> GetAnimatedVisualInvalidatedEventRegistrationTokenTable()" ) ;
603- builder . OpenScope ( ) ;
604- builder . WriteLine ( "return EventRegistrationTokenTable<TypedEventHandler<IDynamicAnimatedVisualSource, object>>.GetOrCreateEventRegistrationTokenTable(ref _animatedVisualInvalidatedEventTokenTable);" ) ;
605- builder . CloseScope ( ) ;
606- }
607- }
608-
609554 /// <summary>
610555 /// Generates the FrameCount property implementation.
611556 /// </summary>
0 commit comments