Skip to content

Commit afd115b

Browse files
authored
Unify the code for cs codegen between IDynamicAVS and regular IAVS (#549)
1 parent c761ef1 commit afd115b

File tree

1 file changed

+124
-179
lines changed

1 file changed

+124
-179
lines changed

source/UIDataCodeGen/CodeGen/CSharp/CSharpInstantiatorGenerator.cs

Lines changed: 124 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)