1
votes

I'm currently working on a Windows Forms GUI and I have a Combo that I need to display a list of string values as the DisplayMembers and use a list of user defined enum values as the ValueMember. I'm currently returning a List> from my database access function and I would like to bind this to my Combo box. I've tried assigning the list to the .DataSource property, assigning "Key" to .DataMember and "Value" to .DisplayMember. This is clearly not a valid approach as it is not working.

Can someone please give me another approach that is in good form and actually works?

Thanks

2

2 Answers

4
votes

I do use my own class EnumPair<> in combination with two extension methods to bind comboboxes to Properties with enum types.

See if this can help you, that you can work directly with the enums.

Use it like this after implementation:

comboBox.BindToEnumValue<MyEnumType>(myBindingSourceInstance, "PropertyNameOfBindingSource");

That assumes you have a ComboBox named "comboBox" on your form, an Enum called "MyEnumType" and an instance of a BindingSource. The PropertyNameOfBindingSource should be the name of the Property of the type that your BindingSource has a list of, that has the PropertyType of MyEnumType. Implementation for the background work is found below, the extension methods are not needed, i just do not like write nearly identical lines of code ;-)

public static class ComboBoxExtensions
{
    public static void BindToEnumValue<TEnum>(this ComboBox cbo, BindingSource bs, string propertyName)
    {
        cbo.DataSource = EnumPair<TEnum>.GetValuePairList();
        cbo.ValueMember = EnumPair<TEnum>.ValueMember;
        cbo.DisplayMember = EnumPair<TEnum>.DisplayMember;
        cbo.DataBindings.Add(new Binding("SelectedValue", bs, propertyName));
    }

    public static void BindClear(this ComboBox cbo)
    {
        cbo.DataSource = null;
        cbo.DataBindings.Clear();
    }
}

/// <summary>
/// Represents a <see cref="EnumPair"/> consisting of an value 
/// of an enum T and a string represantion of the value.
/// </summary>
/// <remarks>
/// With this generic class every <see cref="Enum"/> can be
/// dynamically enhanced by additional values, such as an empty
/// entry, which is usefull in beeing used with 
/// <see cref="ComboBox"/>es.
/// </remarks>
/// <typeparam name="T">The type of the <see cref="Enum"/> to represent.</typeparam>
public partial class EnumPair<T>
{
    #region Constants

    public const string ValueMember = "EnumValue";
    public const string DisplayMember = "EnumStringValue";

    #endregion

    #region Constructor

    /// <summary>
    /// Initializes a new instance of the <see cref="EnumPair"/> class.
    /// </summary>
    public EnumPair()
    {
        Type t = typeof(T);
        if (!t.IsEnum)
        {
            throw new ArgumentException("Class EnumPair<T> can only be instantiated with Enum-Types!");
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="EnumPair"/> class.
    /// </summary>
    /// <param name="value">The value of the enum.</param>
    /// <param name="stringValue">The <see cref="string"/> value of the enum.</param>
    public EnumPair(T value, string stringValue)
    {
        Type t = typeof(T);
        if (!t.IsEnum)
        {
            throw new ArgumentException("Class EnumPair<T> can only be instantiated with Enum-Types!");
        }

        this.EnumValue = value;
        this.EnumStringValue = stringValue;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets or sets the value part of the <see cref="EnumPair"/>.
    /// </summary>
    public T EnumValue { get; set; }

    /// <summary>
    /// Gets or sets the string value of the <see cref="EnumPair"/>.
    /// </summary>
    public string EnumStringValue { get; set; }

    #endregion

    #region Methods

    /// <summary>
    /// Returns a <see cref="string"/> that represents the current <see cref="EnumPair"/>.
    /// </summary>
    public override string ToString()
    {
        return this.EnumStringValue;
    }

    /// <summary>
    /// Generates a <see cref="List<T>"/> of the values
    /// of the <see cref="Enum"/> T.
    /// </summary>
    public static List<EnumPair<T>> GetValuePairList()
    {
        List<EnumPair<T>> list = new List<EnumPair<T>>();
        EnumPair<T> pair = new EnumPair<T>();

        foreach (var item in Enum.GetValues(typeof(T)))
        {
            pair = new EnumPair<T>();
            pair.EnumValue = (T)item;
            pair.EnumStringValue = ((T)item).ToString();
            list.Add(pair);
        }

        return list;
    }

    /// <summary>
    /// Implicit conversion from enum value to <see cref="EnumPair<>"/> from that enum.
    /// </summary>
    /// <param name="e">The enum value to convert to.</param>
    /// <returns>A <see cref="EnumPair<>"/> to the enum value.</returns>
    public static implicit operator EnumPair<T>(T e)
    {
        Type t = typeof(EnumPair<>).MakeGenericType(e.GetType());
        return new EnumPair<T>((T)e, ((T)e).ToString());
    }

    #endregion
}
0
votes

You can try something like this:

ddTemplates.DataSource =
  Enum.GetValues(typeof(EmailTemplateType))
  .Cast<EmailTemplateType>().ToList()
  .Select(v => new KeyValuePair<int, string>((int)v, v.ToString())).ToList();