using System; using System.ComponentModel; using System.Globalization; using System.Reflection; using System.Windows.Data; using System.Collections.Generic; using System.Windows.Controls; namespace MultiTerm.Wpf.ValueConverters; /// /// Converts an Enum (using its Description Attribute) to a Menu Item. /// The Menu Item has the Description assigned to its Header. /// If the Enum has no Description, it will convert the Enum Value to string and use this. /// [ValueConversion(typeof(Enum), typeof(MenuItem))] public class EnumDescriptionToMenuItemConverter : IValueConverter { /// /// Gets the description of an Enum value. /// If there is no Description set, the Enum Value will be converted to string. /// /// Enum Object to get Description of. /// String with Content of DescriptionAttribute of Enum object. private string GetEnumDescription(Enum enumObject) { // guard argument null if(enumObject == null) { throw new ArgumentNullException(nameof(enumObject)); } // get field info from enum type FieldInfo? fieldInfo = enumObject.GetType().GetField(enumObject.ToString()); // return string of enum value if there is no field info if (fieldInfo == null) { return enumObject.ToString(); } // get description attribute and return if it is present DescriptionAttribute? descAttrib = (DescriptionAttribute?)fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute), true); if (descAttrib != null) { return descAttrib.Description; } // if no description attribute was found => return string of enum value return enumObject.ToString(); } /// /// Gets all Description Attributes of a Enum type. /// Descriptions must be unique! /// /// An object of the Enum. Will be searched for other Descriptions /// Key Value Pair of Description and respective Enum Value private Dictionary GetAllEnumDescriptions(Enum enumObject) { // guard argument null if (enumObject == null) { throw new ArgumentNullException(nameof(enumObject)); } Dictionary descriptionsToEnumValues = new(); // get members of enum type var members = enumObject.GetType().GetMembers(); foreach (var member in members) { // get description attributes of all members DescriptionAttribute? descAttrib = (DescriptionAttribute?)member.GetCustomAttribute(typeof(DescriptionAttribute), true); if(descAttrib != null) { // if a description exists, add the description and the enum value to the dictionary descriptionsToEnumValues.Add(descAttrib.Description, (Enum)Enum.Parse(enumObject.GetType(), member.Name)); } } return descriptionsToEnumValues; } /// /// Convert from Data Source to Dependency Object type. /// Here: Enum type to MenuItem. /// /// value to convert /// type to convert to /// no parameter required /// most likely CultureInfo.CurrentCulture /// New MenuItem with Enum description in Header property public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Enum enumValue = (Enum)value; string description = this.GetEnumDescription(enumValue); MenuItem newMenuItem = new() { Header = description }; return newMenuItem; } /// /// Convert from Dependency Object type to Data Source type. /// Here: MenuItem to Enum type. /// /// value to convert /// type to convert to /// no parameter required /// most likely CultureInfo.CurrentCulture /// Enum value of the MenuItem that was converted public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { Enum? enumObj; // guard argument null if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } // extract menu item and guard null MenuItem? menuObject = value as MenuItem; if (menuObject == null) { throw new Exception($"Cannot convert value that is not of type {nameof(MenuItem)} with {nameof(EnumDescriptionToMenuItemConverter)}"); } // generate instance of enum using target type enumObj = Activator.CreateInstance(targetType) as Enum; if (enumObj == null) { throw new Exception($"Could not instanciate Enum of targetType {targetType}."); } // get all enum descriptions and iterate var descriptionToEnumValue = this.GetAllEnumDescriptions(enumObj); foreach (var kvp in descriptionToEnumValue) { // compare key (enum description) to menu header if(String.Compare(kvp.Key, menuObject.Header.ToString(), true) == 0) { // if correct description is found, return according enum value return kvp.Value; } } // if nothing worked => return value return value; } }