Skip to content

Instantly share code, notes, and snippets.

@DamianSuess
Last active October 17, 2025 14:26
Show Gist options
  • Save DamianSuess/4ba5a735302d97ac1a0f7aac4f3f3797 to your computer and use it in GitHub Desktop.
Save DamianSuess/4ba5a735302d97ac1a0f7aac4f3f3797 to your computer and use it in GitHub Desktop.
Avalonia EnumDescriptionConverter Sample - Display Enums in ComboBox

C# XAML (AXAML) ComboBox with Enum Descriptions

This example of how to bind a ComboBox to an enumeration, providing human-readable text in the collection. Please note, this makes use of the Prism Library's SetParameter(...) method which also exist in the CommunityToolkit.

This can be used in XAML-based frameworks such as WPF, Avalonia, .NET MAUI, UNO, etc.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using Avalonia.Data.Converters;
namespace Diagnostics.Converters;
public class EnumDescriptionConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is Enum enumValue)
{
FieldInfo? fieldInfo = enumValue.GetType().GetField(enumValue.ToString());
if (fieldInfo != null)
{
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
////if (attributes.Length > 0 && !string.IsNullOrEmpty(attributes[0].Description))
//// return attributes[0].Description;
if (attributes.Length > 0)
{
foreach (var attr in attributes)
if (attr is DescriptionAttribute descAttr)
return descAttr.Description;
}
}
}
return value?.ToString();
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return string.Empty;
// Optional:
// throw new NotImplementedException();
}
}
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Diagnostics.Converters;assembly=Diagnostics"
...>
<UserControl.Resources>
<ResourceDictionary>
<local:EnumDescriptionConverter x:Key="EnumConverter" />
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding ZoneTypes}" SelectedItem="{Binding ZoneTypeSelected}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</UserControl>
using Prism.Commands;
using Prism.Mvvm;
public class SampleViewModel : BindableBase
{
private ZoneType _zoneTypeSelected;
public ZoneType ZoneTypeSelected { get => _zoneTypeSelected; set => SetProperty(ref _zoneTypeSelected, value); }
public IEnumerable<ZoneType> ZoneTypes => Enum.GetValues<ZoneType>().Cast<ZoneType>();
//// public IEnumerable<ZoneType> ZoneTypes => Enum.GetValues(typeof(ZoneType)).Cast<ZoneType>();
}
using System.ComponentModel;
namespace Diagnostics.Models;
/// <summary>Zone Types.</summary>
public enum ZoneType
{
/// <summary>Unspecified.</summary>
[Description("N/A")]
Unknown = 0,
/// <summary>Upper zone.</summary>
[Description("Upper Zone")]
Zone1,
/// <summary>Middle zone.</summary>
[Description("Middle Zone")]
Zone2,
/// <summary>Bottom zone.</summary>
[Description("Bottom Zone")]
Zone3,
}
# Other Methods from the Internet
## Avalonia Discussion Approach
// Alternative approaches below
// https://github.com/AvaloniaUI/Avalonia/discussions/8175
## AI Slop
The following was generated by Google's AI slop. It does not work, and is here as an example of how not to do things.
```cs
// Throws error when NULL
public class EnumDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Enum)value;
string description = GetEnumDescription(myEnum);
return description;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
private string GetEnumDescription(Enum enumObj)
{
FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
object[] attribArray = fieldInfo.GetCustomAttributes(false);
if (attribArray.Length == 0)
return enumObj.ToString();
else
{
DescriptionAttribute attrib = null;
foreach (var att in attribArray)
{
if (att is DescriptionAttribute)
attrib = att as DescriptionAttribute;
}
if (attrib != null)
return attrib.Description;
return enumObj.ToString();
}
}
}
```
## Overkill EnumDescriptionConverter
```cs
public class EnumDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType().IsEnum)
return ((Enum)value).ToDescription();
throw new ArgumentException("Convert:Value must be an enum.");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is EnumDescription enumDescription)
return enumDescription.Value;
throw new ArgumentException("ConvertBack:EnumDescription must be an enum.");
}
}
public record EnumDescription
{
public object Value { get; set; }
public string Description { get; set; }
public string Help { get; set; }
public override string ToString()
{
return Description;
}
}
public static class EnumUtils
{
public static IEnumerable<EnumDescription> ToDescriptions(Type t)
{
if (!t.IsEnum)
throw new ArgumentException($"{nameof(t)} must be an enum type");
return Enum.GetValues(t).Cast<Enum>().Select(ToDescription).ToList();
}
public static EnumDescription ToDescription(this Enum value)
{
string description;
string help = null;
var attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Any())
{
description = (attributes.First() as DescriptionAttribute)?.Description;
}
else
{
TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
description = ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
}
if (description.IndexOf(';') is var index && index != -1)
{
help = description.Substring(index + 1);
description = description.Substring(0, index);
}
return new EnumDescription() { Value = value, Description = description, Help = help };
}
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();
FieldInfo fi = type.GetField(value.ToString());
if (fi.GetCustomAttributes(typeof(StringValue),
false) is StringValue[] { Length: > 0 } attrs)
{
output = attrs[0].Value;
}
return output;
}
public static T? Parse<T>(string input) where T : struct
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Generic Type 'T' must be an Enum.");
}
if (string.IsNullOrEmpty(input))
return null;
if (Enum.GetNames(typeof(T)).Any(
e => e.Trim().ToUpperInvariant() == input.Trim().ToUpperInvariant()))
{
return (T)Enum.Parse(typeof(T), input, true);
}
return null;
}
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment