Reputation: 1366
This is just an investigation into the best way to format string values on a ComboBox
originating from an Enum
.
I know I can databind a ComboBox
to an Enum
like so:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
comboBoxNames.DataSource = Enum.GetValues(typeof (Names));
}
}
public enum Names
{
JohnDoe,
JaneDoe,
JohnJackson,
JackJohnson
}
This is the result:
I would like to format the display values of the ComboBox
such that there is a space between the PascalCase string values, while also passing through the Enum
value of the selected item which I can use in a switch
statement later on:
switch ((Names)comboBoxNames.SelectedItem)
{
case Names.JohnDoe:
// Do something John Doe-specific
break;
case Names.JaneDoe:
// Do something Jane Doe-specific
break;
case Names.JohnJackson:
// Do something John Jackson-specific
break;
case Names.JackJohnson:
// Do something Jack Johnson-specific
break;
}
I know that there is a ComboBox.FormatString
property but I am unsure about how to use it to format the Names
enum the way that I want.
Is this possible? I would prefer not to use attributes on the Enum
because using that ultimately involves using reflection which seems like overkill for something that seems so simple. Any help would be much appreciated.
Upvotes: 1
Views: 966
Reputation: 1366
I have figured out a way to format string values on a ComboBox
originating from an Enum
that I like, without requiring the ComboBox.FormatString
property or the Format
event: use a Dictionary<Enum, string>
. Sample code below:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
comboBoxNames.DataBindToEnum(default(Names).ToDictionary());
}
private void btnOK_Click(object sender, EventArgs e)
{
switch (((KeyValuePair<Names, string>)comboBoxNames.SelectedItem).Key)
{
case Names.JohnDoe:
// Do something John Doe-specific
MessageBox.Show(@"John Doe!");
break;
case Names.JaneDoe:
// Do something Jane Doe-specific
MessageBox.Show(@"Jane Doe!");
break;
case Names.JohnJackson:
// Do something John Jackson-specific
MessageBox.Show(@"John Jackson!");
break;
case Names.JackJohnson:
// Do something Jack Johnson-specific
MessageBox.Show(@"Jack Johnson!");
break;
}
}
}
public enum Names
{
JohnDoe,
JaneDoe,
JohnJackson,
JackJohnson
}
public static class EnumExtensions
{
public static Dictionary<T, string> ToDictionary<T>(this T enumeration)
{
if (!enumeration.GetType().IsEnum) return null;
var enumValues = Enum.GetValues(typeof(T)).OfType<T>().ToList();
return enumValues.ToDictionary(enumValue => enumValue, enumValue => enumValue.ToString().Spaceify());
}
}
public static class StringExtensions
{
public static string Spaceify(this string self)
{
for (var i = 1; i < self.Length - 1; i++)
{
if (char.IsLower(self[i - 1]) && char.IsUpper(self[i]) ||
self[i - 1] != ' ' && char.IsUpper(self[i]) && char.IsLower(self[i + 1]))
{
self = self.Insert(i, " ");
}
}
return self;
}
}
public static class ControlExtensions
{
public static void DataBindToEnum<T>(this ListControl listControl, IDictionary<T, string> enumAsDictionary)
{
listControl.DataSource = new BindingSource(enumAsDictionary, null);
listControl.DisplayMember = "Value";
listControl.ValueMember = "Key";
}
}
A couple of things to note:
ComboBox.DataSource
directly as a list of the enum
, set it using a Dictionary<Enum, string>
and set the DisplayMember
and ValueMember
accordingly (extension method DataBindToEnum
)enum
keyword as a type restriction (something like public static Dictionary<T, string> ToDictionary<T>(this T enumeration) **where T : enum**
). This is why an enum
check is required in the body of that methodSpaceify
extension method adds spaces to PascalCase strings (handles acronyms as well)default
keyword on the enum
so that I can work on it as a list-type object and get around the issue of invoking a method on an "instance" of the enum
ComboBox.SelectedItem
I need to cast it to a KeyValuePair<Enum, string>
and pull out the Key
which I can use in my switch
statement. No more magic strings!Hope this helps!
Upvotes: 0
Reputation: 10552
this is easy, just add the format event on your combobox and make it look like this:
private void comboBoxNames_Format(object sender, ListControlConvertEventArgs e)
{
StringBuilder newText = new StringBuilder(e.Value.ToString().Length +1);
newText.Append(e.Value.ToString()[0]);
for (int i = 1; i < e.Value.ToString().Length; i++)
{
if (char.IsUpper(e.Value.ToString()[i]) && e.Value.ToString()[i - 1] != ' ')
newText.Append(' ');
newText.Append(e.Value.ToString()[i]);
}
e.Value = newText.ToString();
}
Upvotes: 1