Note: Code is formatted to fit SO's design, not necessarily the typical C# line (break) design as I dislike horizontal scrolling.
The resources file, Resources.resx:

Note #1: You must set the Access Modifier (upper right corner in the screenshot above) to Public in order to get access from other assemblies (which is required in my case).
Note #2: To leverage Visual Studio's concept of multi-language support, a localized resources file must be named Resources.xx-XX.resx, e. g. Resources.de-DE.resx.
The enum
, QuestionType.cs:
namespace Yoda.Data.Interfaces.Enums
{
using System.ComponentModel.DataAnnotations;
using Yoda.Data.Interfaces.Properties;
public enum QuestionType
{
[Display(Name = "Question_Type_Unknown_Entry",
ResourceType = typeof(Resources),
Description = "Question_Type_Unknown_ToolTip")]
Unknown = 0,
[Display(Name = "Question_Type_Question_Entry",
ResourceType = typeof(Resources),
Description = "Question_Type_Question_ToolTip")]
Question = 1,
[Display(Name = "Question_Type_Answer_Entry",
ResourceType = typeof(Resources),
Description = "Question_Type_Answer_ToolTip")]
Answer = 2
}
}
The extension method(s) in EnumExtensions.cs:
namespace Yoda.Frontend.Extensions
{
using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Resources;
public static class EnumExtensions
{
// This method can be made private if you don't use it elsewhere
public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumValue)
where TAttribute : Attribute
{
var memberInfo = enumValue.GetType().GetMember(enumValue.ToString());
return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false)
.OfType<TAttribute>()
.FirstOrDefault();
}
public static string ToDescription(this Enum enumValue)
{
var displayAttribute = enumValue.GetEnumAttribute<DisplayAttribute>();
return displayAttribute == null
? enumValue.ToString().Replace("_", " ")
: new ResourceManager(displayAttribute.ResourceType)
.GetString(displayAttribute.Description, CultureInfo.CurrentUICulture);
}
public static string ToName(this Enum enumValue)
{
var displayAttribute = enumValue.GetEnumAttribute<DisplayAttribute>();
return displayAttribute == null
? enumValue.ToString().Replace("_", " ")
: new ResourceManager(displayAttribute.ResourceType)
.GetString(displayAttribute.Name, CultureInfo.CurrentUICulture);
}
}
// Your other enum extension methods go here...
}
An usage example in WPF requiring 2 converters (instead of one with parameter) to comply with SoC would look like the following:
The Name
property converter, QuestionTypeNameConverter.cs:
namespace Yoda.Frontend.Converters
{
using System;
using System.Globalization;
using System.Windows.Data;
using Yoda.Data.Interfaces.Enums;
using Yoda.Frontend.Extensions;
// Second converter would be named QuestionTypeDescriptionConverter
public class QuestionTypeNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
// Second converter would call .ToDescription() instead
return (value as QuestionType? ?? QuestionType.Unknown).ToName();
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
return value;
}
}
}
Note: For your reading pleasure, I'm limiting my example to only show one converter class, but I've included comments to describe needed changes for the second one.
And finally the usage in MainView.xaml:
<Window x:Class="Yoda.Frontend.MainView" x:Name="MainWindow">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
// ... more xmlns & other basic stuff
xmlns:c="clr-namespace:CAP.GUI.Converters"
<Window.Resources>
<c:QuestionTypeDescriptionConverter x:Key="QuestionTypeDescription" />
<c:QuestionTypeNameConverter x:Key="QuestionTypeName" />
</Window.Resources>
// Your window layout goes here...
<ComboBox ItemsSource="{Binding QuestionTypes, Mode=OneWay}" Margin="3" Name="QuestionType"
SelectedItem="{Binding SelectedItem.ValidQuestionType,
Converter={StaticResource QuestionTypeName}}"
ToolTip="{Binding SelectedItem.ValidQuestionType,
Converter={StaticResource QuestionTypeDescription}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource QuestionTypeName}}"
ToolTip="{Binding Converter={StaticResource QuestionTypeDescription}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
// Your other window layout goes here...
</Window>