Skip to content

Add New Enum Description Converter#3137

Open
BillyMartin1964 wants to merge 8 commits intoCommunityToolkit:mainfrom
BillyMartin1964:main
Open

Add New Enum Description Converter#3137
BillyMartin1964 wants to merge 8 commits intoCommunityToolkit:mainfrom
BillyMartin1964:main

Conversation

@BillyMartin1964
Copy link

This converter converts Enum values into readable text so they display nicely in the UI. When an Enum value is passed in, the converter looks for attributes that provide a more user-friendly name. If one is found, it uses that value; otherwise it simply uses the Enum’s name. This ensures that Enum values can be displayed clearly while still working correctly even when no attributes are defined. Unit tests are included to verify the expected behavior.

Description of Change

Added new converter

Linked Issues

  • Fixes #

PR Checklist

  • Has a linked Issue, and the Issue has been approved(bug) or Championed (feature/proposal)
  • Has tests (if omitted, state reason in description)
  • Has samples (if omitted, state reason in description)
  • Rebased on top of main at time of PR
  • Changes adhere to coding standard
  • Documentation created or updated: https://github.com/MicrosoftDocs/CommunityToolkit/pulls

Additional information

Example use case:

 Text="{Binding SelectedModeName, Converter={StaticResource EnumDescriptionConverter}}"

public enum ModeName
{
    [Display(Name = "Light  Mode")]
    LightMode,
    [Display(Name = "Dark  Mode")]
    DarkMode,
    [Display(Name = "System")]
    System
}

This converter transforms Enum values into strings by checking for DisplayAttribute or DescriptionAttribute. It prioritizes the Name property of DisplayAttribute, then the Description property of DescriptionAttribute, and finally falls back to the Enum's string representation. Unit tests are included to verify attribute precedence, whitespace handling, and fallback behavior.
Copilot AI review requested due to automatic review settings March 10, 2026 06:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new value converter to the CommunityToolkit.Maui converters set to turn Enum values into user-friendly strings for UI display, with unit tests validating expected attribute precedence and fallbacks.

Changes:

  • Introduces EnumDescriptionConverter that prefers DisplayAttribute, then DescriptionAttribute, then falls back to Enum.ToString().
  • Adds unit tests covering attribute precedence and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/CommunityToolkit.Maui/Converters/EnumDescriptionConverter.cs New converter for mapping enum values to display-friendly strings via attributes.
src/CommunityToolkit.Maui.UnitTests/Converters/EnumDescriptionConverterTests.cs Unit tests for the new converter’s attribute selection and fallback logic.

@BillyMartin1964
Copy link
Author

There is a PR for the documentation at:

MicrosoftDocs/CommunityToolkit#622

The converter now uses the GetName method on DisplayAttribute to retrieve localized strings when a ResourceType is provided. It includes fallback logic for cases where the resource is missing, the display name is whitespace, or the GetName method throws an exception. New unit tests verify these localization scenarios and edge cases for both DisplayAttribute and DescriptionAttribute.
Update EnumDescriptionConverterTests to inherit from BaseOneWayConverterTest to align with standard value converter tests.
Update the ConvertFrom_ThrowsArgumentNullException_WhenNull test in EnumDescriptionConverterTests.cs to cast the converter to ICommunityToolkitValueConverter and invoke the Convert method.
@BillyMartin1964
Copy link
Author

BillyMartin1964 commented Mar 10, 2026 via email

Copy link
Collaborator

@TheCodeTraveler TheCodeTraveler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @BillyMartin1964.

I'm a bit confused by the scope of this Converter and would like to avoid using Reflection.

Scope

Does it get the DescriptionAttribute or does it get DisplayAttribute.Name?

To put yourself in another developer's shoes, if you saw a converter named EnumDescriptionConverter as you're scrolling through intellisense, what would you assume it would do? Devs don't always read docs, so naming + scope is critically important.

It's named the EnumDescriptionConverter which implies it will return the DescriptionAttribute, but this current implementation may return three different results without providing any control to the developer over which results comes back:

  • DescriptionAttribute
  • DisplayAttribute.Name
  • Enum name

We should not return the enum name as that will cause confusion to the developer who expected its description. Instead, it should return null to indicate to the developer that no attribute was found, or throw an InvalidOperationException if we decide this converter does not support enums without descriptions.

After that fix, I see two paths forward for this new converter:

  1. Separate this into two separate converters:
    • EnumDescriptionConverter : BaseConverterOneWay<Enum, string?>
    • EnumDisplayNameConverter : BaseConverterOneWay<Enum, string?>
  2. Create an enum that allows the developer to choose which value is returned
  • This would be similar to our implementation for the CompareConverter StringToListConverter and how it allows developers customization via its enum OperatorType

Reflection

I don't love that the current implementation is using reflection which limits the abilities for AOT compiling. Is this possible without Reflection?

Have you confirmed this runs works on an iOS Device built in Release configuration without the Mono Interpreter? And have you confirmed this works in an AOT'd code base?

New Feature Proposal Process

In the future, before submitting a PR implementing a feature and before writing the docs for it, I recommend following our process for Submitting a New Feature . You've skipped the Proposal phase where we would've had this discussion about its implementation and saved time and re-work.

{
ArgumentNullException.ThrowIfNull(value);
var fieldInfo = value.GetType().GetField(value.ToString());

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this possible without reflection?

public partial class EnumDescriptionConverter : BaseConverterOneWay<Enum, string>
{
/// <inheritdoc/>
public override string DefaultConvertReturnValue { get; set; } = string.Empty;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public override string DefaultConvertReturnValue { get; set; } = string.Empty;
public override string? DefaultConvertReturnValue { get; set; }

It would make sense for this converter to return a nullable string and return null when an enum does not contain a Description attribute.

/// Converts an <see cref="Enum"/> value to its display string using <see cref="DisplayAttribute"/> or <see cref="DescriptionAttribute"/>.
/// </summary>
[AcceptEmptyServiceProvider]
public partial class EnumDescriptionConverter : BaseConverterOneWay<Enum, string>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public partial class EnumDescriptionConverter : BaseConverterOneWay<Enum, string>
public partial class EnumDescriptionConverter : BaseConverterOneWay<Enum, string?>

It would make sense for this converter to return a nullable string, BaseConverterOneWay<Enum, string?> and return null when an enum does not contain a Description attribute.

/// otherwise the value of the <see cref="DescriptionAttribute.Description"/> if defined;
/// otherwise the enum name as a string.
/// </returns>
public override string ConvertFrom(Enum value, CultureInfo? culture = null)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public override string ConvertFrom(Enum value, CultureInfo? culture = null)
public override string? ConvertFrom(Enum value, CultureInfo? culture = null)

It would make sense for this converter to return a nullable string and return null when an enum does not contain a Description attribute.

return descriptionAttr.Description;
}

return value.ToString(); // Fallback to enum name if no attribute found
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return value.ToString(); // Fallback to enum name if no attribute found
return value.ToString(); // Fallback to enum name if no attribute found

It would make sense for this converter to return a nullable string and return null when an enum does not contain a Description attribute.

@TheCodeTraveler TheCodeTraveler added the needs discussion Discuss it on the next Monthly standup label Mar 10, 2026
@BillyMartin1964
Copy link
Author

BillyMartin1964 commented Mar 10, 2026

I wrote this converter for my own use, when I realized there wasn't one in the toolkit. It's really quite handy, and I thought I would share it with the community. I did open a discussion, and asked James Montemagno to champion it, but he said to just send the problem.

Here's the discussion link:

#3136

I don't really see the problem with a tiny converter. I tried to cover all the bases. Some devs use display name, some use description, and some use localization. We could make three converters if you want.

It really doesn't matter to me as long as it ends up in the toolkit. I think it's quite a useful converter. Also, if you want to finish it up, that's fine too. Just let me know. Happy to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs discussion Discuss it on the next Monthly standup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants