Skip to content

Commit c4bda26

Browse files
committed
Refactor GetDefaultValueCreatorMethod. Update XML Doc. Apply to readonly BindableProperty. Extend unit test.
1 parent 6ddcd78 commit c4bda26

File tree

2 files changed

+67
-16
lines changed

2 files changed

+67
-16
lines changed

src/CommunityToolkit.Maui.SourceGenerators.Internal.UnitTests/BindablePropertyAttributeSourceGeneratorTests/CommonUsageTests.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,13 +663,17 @@ public async Task GenerateBindableProperty_WithInitializers_GeneratesCorrectCode
663663
$$"""
664664
using CommunityToolkit.Maui;
665665
using Microsoft.Maui.Controls;
666+
using System;
666667
667668
namespace {{defaultTestNamespace}};
668669
669670
public partial class {{defaultTestClassName}} : View
670671
{
671672
[BindablePropertyAttribute]
672673
public partial string Text { get; set; } = "Initial Value";
674+
675+
[BindablePropertyAttribute]
676+
public partial TimeSpan CustomDuration { get; set; } = TimeSpan.FromSeconds(30);
673677
}
674678
""";
675679

@@ -689,15 +693,30 @@ public partial class {{defaultTestClassName}}
689693
/// </summary>
690694
public static readonly global::Microsoft.Maui.Controls.BindableProperty TextProperty = global::Microsoft.Maui.Controls.BindableProperty.Create("Text", typeof(string), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, __createDefaultText);
691695
bool __initializingText = false;
692-
public partial string Text { get => __initializingText ? field : (string)GetValue(TextProperty); set => SetValue(TextProperty, field = value); }
693-
694696
static object __createDefaultText(Microsoft.Maui.Controls.BindableObject bindable)
695697
{
696698
(({{defaultTestClassName}})bindable).__initializingText = true;
697699
var defaultValue = (({{defaultTestClassName}})bindable).Text;
698700
(({{defaultTestClassName}})bindable).__initializingText = false;
699701
return defaultValue;
700702
}
703+
704+
public partial string Text { get => __initializingText ? field : (string)GetValue(TextProperty); set => SetValue(TextProperty, field = value); }
705+
706+
/// <summary>
707+
/// Backing BindableProperty for the <see cref = "CustomDuration"/> property.
708+
/// </summary>
709+
public static readonly global::Microsoft.Maui.Controls.BindableProperty CustomDurationProperty = global::Microsoft.Maui.Controls.BindableProperty.Create("CustomDuration", typeof(System.TimeSpan), typeof({{defaultTestNamespace}}.{{defaultTestClassName}}), null, Microsoft.Maui.Controls.BindingMode.OneWay, null, null, null, null, __createDefaultCustomDuration);
710+
bool __initializingCustomDuration = false;
711+
static object __createDefaultCustomDuration(Microsoft.Maui.Controls.BindableObject bindable)
712+
{
713+
(({{defaultTestClassName}})bindable).__initializingCustomDuration = true;
714+
var defaultValue = (({{defaultTestClassName}})bindable).CustomDuration;
715+
(({{defaultTestClassName}})bindable).__initializingCustomDuration = false;
716+
return defaultValue;
717+
}
718+
719+
public partial System.TimeSpan CustomDuration { get => __initializingCustomDuration ? field : (System.TimeSpan)GetValue(CustomDurationProperty); set => SetValue(CustomDurationProperty, field = value); }
701720
}
702721
""";
703722

src/CommunityToolkit.Maui.SourceGenerators.Internal/Generators/BindablePropertyAttributeSourceGenerator.cs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,13 @@ static string GenerateSource(SemanticValues value)
183183
GenerateBindableProperty(sb, in info);
184184
}
185185

186-
GenerateProperty(sb, in info);
187-
188186
if (info.HasInitializer)
189187
{
188+
GenerateInitializingProperty(sb, in info);
190189
GenerateDefaultValueMethod(sb, in info, classNameWithGenerics);
191190
}
191+
192+
GenerateProperty(sb, in info);
192193
}
193194

194195
sb.Append('}');
@@ -241,7 +242,7 @@ static void GenerateReadOnlyBindableProperty(StringBuilder sb, in BindableProper
241242
.Append(", ")
242243
.Append(info.CoerceValueMethodName)
243244
.Append(", ")
244-
.Append(info.DefaultValueCreatorMethodName)
245+
.Append(GetDefaulteValueCreatorMethod(in info))
245246
.Append(");\n");
246247

247248
// Generate public BindableProperty from the key
@@ -297,7 +298,7 @@ static void GenerateBindableProperty(StringBuilder sb, in BindablePropertyModel
297298
.Append(", ")
298299
.Append(info.CoerceValueMethodName)
299300
.Append(", ")
300-
.Append(info.HasInitializer ? "__createDefault" + info.PropertyName : info.DefaultValueCreatorMethodName)
301+
.Append(GetDefaulteValueCreatorMethod(in info))
301302
.Append(");\n");
302303

303304
sb.Append('\n');
@@ -309,14 +310,6 @@ static void GenerateProperty(StringBuilder sb, in BindablePropertyModel info)
309310
var sanitizedPropertyName = IsDotnetKeyword(info.PropertyName) ? string.Concat("@", info.PropertyName) : info.PropertyName;
310311
var formattedReturnType = GetFormattedReturnType(info.ReturnType);
311312

312-
if (info.HasInitializer)
313-
{
314-
sb.Append("bool ")
315-
.Append("__initializing")
316-
.Append(info.PropertyName)
317-
.Append(" = false;\n");
318-
}
319-
320313
sb.Append("public ")
321314
.Append(info.NewKeywordText)
322315
.Append("partial ")
@@ -568,13 +561,52 @@ static string GetFormattedReturnType(ITypeSymbol typeSymbol)
568561
}
569562
}
570563

564+
/// <summary>
565+
/// Determines the name of the method used to create the default value for the specified bindable property model.
566+
/// </summary>
567+
/// <param name="info">The bindable property model for which to retrieve the default value creator method name.</param>
568+
/// <returns>A string containing the name of the method that creates the default value for the property.
569+
/// If the property has an initializer, the returned name is of the generated default value method;
570+
/// otherwise, the default value creator method name from the model is returned.</returns>
571+
static string GetDefaulteValueCreatorMethod(in BindablePropertyModel info)
572+
{
573+
if (info.HasInitializer)
574+
{
575+
return "__createDefault" + info.PropertyName;
576+
}
577+
578+
return info.DefaultValueCreatorMethodName;
579+
}
580+
581+
/// <summary>
582+
/// Generates the boolean initialization flag used by bindable properties with initializers to indicate that the getter
583+
/// should return the backing field while the generated default value method is executing.
584+
/// </summary>
585+
/// <param name="sb">The StringBuilder instance to which the initialization field declaration will be appended.</param>
586+
/// <param name="info">The model containing metadata about the property for which the initialization field is generated.</param>
587+
static void GenerateInitializingProperty(StringBuilder sb, in BindablePropertyModel info)
588+
{
589+
sb.Append("bool ")
590+
.Append("__initializing")
591+
.Append(info.PropertyName)
592+
.Append(" = false;\n");
593+
}
594+
595+
/// <summary>
596+
/// Generates the default value creator static method used by BindableProperty instances with initializers.
597+
/// This method temporarily switches the property's getter to return its backing field while the default value is being computed,
598+
/// ensuring that the initializer-provided value is captured and returned as the BindableProperty's default.
599+
/// </summary>
600+
/// <param name="sb">The StringBuilder instance to which the initialization field declaration will be appended.</param>
601+
/// <param name="info">The model containing metadata for the property that requires a default value creator.</param>
602+
/// <param name="classNameWithGenerics">The declaring class name including generic type parameters, if any.</param>
571603
[MethodImpl(MethodImplOptions.AggressiveInlining)]
572604
static void GenerateDefaultValueMethod(StringBuilder sb, in BindablePropertyModel info, string classNameWithGenerics)
573605
{
574606
var sanitizedPropertyName = IsDotnetKeyword(info.PropertyName) ? string.Concat("@", info.PropertyName) : info.PropertyName;
575607

576-
sb.Append("static object __createDefault")
577-
.Append(info.PropertyName)
608+
sb.Append("static object ")
609+
.Append(GetDefaulteValueCreatorMethod(in info))
578610
.Append("(Microsoft.Maui.Controls.BindableObject bindable)\n")
579611
.Append("{\n")
580612
.Append("((")

0 commit comments

Comments
 (0)