Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for custom name in ObservablePropertyAttribute #917

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ internal static class Execute
/// <param name="token">The cancellation token for the current operation.</param>
/// <param name="propertyInfo">The resulting <see cref="PropertyInfo"/> value, if successfully retrieved.</param>
/// <param name="diagnostics">The resulting diagnostics from the processing operation.</param>
/// <param name="PropertyName">Generated property name. If empty, the property name will be generated from the field name.</param>
/// <returns>The resulting <see cref="PropertyInfo"/> instance for <paramref name="fieldSymbol"/>, if successful.</returns>
public static bool TryGetInfo(
FieldDeclarationSyntax fieldSyntax,
IFieldSymbol fieldSymbol,
SemanticModel semanticModel,
CancellationToken token,
string PropertyName,
[NotNullWhen(true)] out PropertyInfo? propertyInfo,
out ImmutableArray<DiagnosticInfo> diagnostics)
{
Expand All @@ -69,7 +71,8 @@ public static bool TryGetInfo(
// Get the property type and name
string typeNameWithNullabilityAnnotations = fieldSymbol.Type.GetFullyQualifiedNameWithNullabilityAnnotations();
string fieldName = fieldSymbol.Name;
string propertyName = GetGeneratedPropertyName(fieldSymbol);
// Generate if not specified
string propertyName = string.IsNullOrEmpty(PropertyName) ? GetGeneratedPropertyName(fieldSymbol) : PropertyName;

// Check for name collisions
if (fieldName == propertyName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

token.ThrowIfCancellationRequested();

_ = Execute.TryGetInfo(fieldDeclaration, fieldSymbol, context.SemanticModel, token, out PropertyInfo? propertyInfo, out ImmutableArray<DiagnosticInfo> diagnostics);
string propertyName = context.Attributes.FirstOrDefault()?.GetConstructorArguments<string>().FirstOrDefault() ?? string.Empty;;

_ = Execute.TryGetInfo(fieldDeclaration, fieldSymbol, context.SemanticModel, token, propertyName, out PropertyInfo? propertyInfo, out ImmutableArray<DiagnosticInfo> diagnostics);

token.ThrowIfCancellationRequested();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,24 @@ namespace CommunityToolkit.Mvvm.ComponentModel;
/// The generated properties will automatically use the <c>UpperCamelCase</c> format for their names,
/// which will be derived from the field names. The generator can also recognize fields using either
/// the <c>_lowerCamel</c> or <c>m_lowerCamel</c> naming scheme. Otherwise, the first character in the
/// source field name will be converted to uppercase (eg. <c>isEnabled</c> to <c>IsEnabled</c>).
/// source field name will be converted to uppercase (eg. <c>isEnabled</c> to <c>IsEnabled</c>). For
/// custom property names use the <see cref="ObservablePropertyAttribute(string)"/>
/// </remarks>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public sealed class ObservablePropertyAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ObservablePropertyAttribute"/> class.
/// </summary>
public ObservablePropertyAttribute()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ObservablePropertyAttribute"/> class.
/// </summary>
/// <param name="name">Generated property name.</param>
public ObservablePropertyAttribute(string name)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,22 @@ public void Test_ObservableProperty_ForwardedAttributesWithNegativeValues()
.Value);
}

// See https://github.com/CommunityToolkit/dotnet/issues/795
[TestMethod]
public void Test_ObservableProperty_ModelWithPropertyNames()
{
ModelWithPropertyNames model = new();

List<string?> propertyNames = new();

model.PropertyChanged += (s, e) => propertyNames.Add(e.PropertyName);

CollectionAssert.AreEqual(new[]
{
nameof(model.fieldProp),
}, propertyNames);
}

public abstract partial class BaseViewModel : ObservableObject
{
public string? Content { get; set; }
Expand Down Expand Up @@ -1797,4 +1813,11 @@ private sealed partial class ModelWithDependentPropertyAndNoPropertyChanging

public string? FullName => "";
}

public partial class ModelWithPropertyNames : ObservableObject
{
// Inherited property
[ObservableProperty("fieldProp")]
private string? m_field;
}
}