I had to jump through some hoops to get a localized enum working. I went through dozens of SO articles that never actually answered the relevant conundrum with a working solution. So I made my own:
I have two resource files: LocalizedStrings.resx and LocalizedStrings.es-MX.resx With two corresponding lines:
GENDER_FEMALE Female
GENDER_MALE Male
... and ...
GENDER_FEMALE Mujer
GENDER_MALE Hombre
... respectively.
I have an Enum Extension:
public static class EnumExtensionMethods
{
public static string GetDisplay(this Enum enumValue)
{
object[] attr = enumValue.GetType().GetField(enumValue.ToString())
.GetCustomAttributes(typeof(DisplayAttribute), false);
return attr.Length > 0
? ((DisplayAttribute)attr[0]).GetName()
: enumValue.ToString();
}
}
My actual Enum:
public enum Gender
{
[Display(ResourceType = typeof(LocalizedStrings), Name = "GENDER_MALE")]
Male = 1,
[Display(ResourceType = typeof(LocalizedStrings), Name = "GENDER_FEMALE")]
Female = 0
}
I load the values into a Winforms ComboBox’s items, (I could not get binding it to an entity to work) with the OnLoad event:
foreach (Gender value in Enum.GetValues(typeof(Gender)))
{
GenderComboBox.Items.Add(new KeyValuePair<string, Gender>(value.GetDisplay(), value));
}
GenderComboBox.DisplayMember = "Key";
GenderComboBox.ValueMember = "Value";
GenderComboBox.SelectedIndex = 1;
Finally, I have to set the entity value with this event:
private void GenderComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (!GenderComboBox.Focused)
return;
if (GenderComboBox.SelectedIndex == -1)
return;
KeyValuePair<string, Gender> gender = (KeyValuePair<string, Gender>) GenderComboBox.SelectedItem;
Person person = (Person)PersonBindingSource.Current;
person.Gender = gender.Value;
}
All of the previous code just to get a Localized Enum. Is there not a better way?
1 Answer 1
You really shouldn't mix event and data-binding together.
The proper way of updating value from UI, would be using ComboBox.DataBindings.Add(Binding)
. And, not patching it via ComboBox.SelectedSomethingChanged
.
Here is how I would do it :
// mock model
var person = new Person { Gender = Gender.Female };;
// mock data source
var personBindingSource = new BindingSource();
personBindingSource.DataSource = new List<Person> { person };
// initialize
var combo = new ComboBox();
// you may want to set DropDownStyle to ComboBoxStyle.DropDownList
// from the designer to disable text input.
//
// choose one of the two below :
// combo.DisplayMember = "Value";
// combo.ValueMember = "Key";
// combo.DataSource = EnumHelper.GetEnumDefinitions<Gender>();
combo.BindTo<Gender>();
// databind
combo.DataBindings.Add(new Binding(
nameof(combo.SelectedValue), personBindingSource, nameof(person.Gender), false, DataSourceUpdateMode.OnPropertyChanged));
public static class EnumHelper
{
public static IList GetEnumDefinitions<TEnum>()
where TEnum : struct, IConvertible
{
var type = typeof(TEnum);
if (!type.IsEnum)
throw new ArgumentException($"'{type}' is not an enum type.");
return type
.GetFields(BindingFlags.Public | BindingFlags.Static)
.ToDictionary(x => (TEnum)x.GetValue(null), x =>
x.GetCustomAttribute<DisplayAttribute>()?.GetName() ?? x.GetValue(null).ToString()
)
.ToList();
}
public static void BindTo<TEnum>(this ComboBox combo)
where TEnum : struct, IConvertible
{
combo.DisplayMember = "Value";
combo.ValueMember = "Key";
combo.DataSource = EnumHelper.GetEnumDefinitions<TEnum>();
}
}
Explore related questions
See similar questions with these tags.