views:

805

answers:

1

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  A: 

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
}
BeowulfOF
I need to look a little closer and try some things but I think this accomplishes what I'm going for.Thanks. I will accept this answer if it does in fact solve my issue.
TJ_Fischer
OK, so I'm pretty sure this is working but it took me a while understand your code. It's great code, but a snippet of example code that makes use of these classes would be super helpful for future readers. Any chance you could provide that as well?
TJ_Fischer
I do not have an development environment here at home, but next week I can paste some more code sample to this. For now my additional hints are all I can give you. Have a nice Weekend.
BeowulfOF
Hitted it exactly as used in productiv code, so no more code samples possible here. Hope it is useful, though.
BeowulfOF
If you look at my original question I have a KeyValuePair with a String which is what I want displayed in the combo box and a enum which I want is value I want to use when the combo is selected.While your code works it displays the name of the enumeration. However, I'm trying to display a different string value in the combo box rather than the name of the enum. Is your approach made to allow that? How would I make that happen?
TJ_Fischer
Simply substitute my EnumPair class with your KeyValuePair, should work like a charm.
BeowulfOF