Enum als Datasource für DataGridViewComboBoxColumn im DataGridView verwenden

Vor längerer Zeit habe ich in diesem Artikel berichtet wie man enum Werte über die DataSource Eigenschaft an eine Combobox binden kann.

Hier eine Darstellung einer solchen Bindung in einer normalen Windows Form:

Will man nun aber enum Werte in einem DataGridview an eine, als Combobox definierte, Spalte (DataGridViewComboBoxColumn) binden, geht das nicht ganz so einfach, und eben nicht so wie es in meinem oben erwähnten Artikel beschrieben ist.

Das Ergebnis soll so aussehen:

Wer schon einmal eine solche Tabelle programmiert hat, weiß, dass man nachdem man die DataSource Eigenschaft der DataGridViewComboBoxColumn zugewiesen hat, noch den ValueMember und den DisplayMember angeben muss (Siehe nachfolgende Abbildung).

Da wir die DataSource Eigenschaft bei der enum Variante über den Source Code zuweisen (es geht auch anders, dazu evtl. zu einem späteren Zeitpunkt mal mehr), müssen wir natürlich auch die beiden Eigenschaften  DisplayMember und ValueMember aus dem Quellcode heraus zuweisen.

Nur wie heißen die denn ?

Und genau hier liegt das Problem, bzw. die hier beschriebene Lösung.

Diese Eigenschaften gibt es bei der ursprünglich von mir beschriebenen Lösung nicht.

Und daher müssen wir uns solche Eigenschaften bilden. Hierzu verwenden ich eine Helper Klasse die das notwendige implementiert. (Siehe nachfolgenden Source Code)

Hier nun der Code der Klassen

[Serializable]
public class EnumHelper
{
	public int Key { get; set; }
	public string Value { get; set; }

	public static IEnumerable<ValueListItem> CreateDataSourceFromEnum(Type t)
	{
		var list = new List<ValueListItem>();

		Array aEnum = Enum.GetValues(t);
		foreach (var array in aEnum)
		{
			var vi = new ValueListItem
						 {
							 Key = (int) array,
							 Value = array.ToString()
						 };

			list.Add(vi);
		}
		return list;
	}

	public static IEnumerable<EnumHelper> DataSourceFromEnum(Type t)
	{
		var list = new List<EnumHelper>();

		Array aEnum = Enum.GetValues(t);
		foreach (var array in aEnum)
		{
			var vi = new EnumHelper
						 {
							 Key = (int) array,
							 Value = array.ToString()
						 };

			list.Add(vi);
		}
		return list;
	}

}

[Serializable]
public class ValueListItem
{
	public int Key { get; set; }
	public string Value { get; set; }
}

Und so kann man die Helper Klasse verwenden um die DataSource Eigenschaft sowie die ValueMember und DisplayMember Eigenschaften zuzuweisen.

private void InitDgv()
{
	bereichDataGridViewTextBoxColumn.DataSource = EnumHelper.DataSourceFromEnum(typeof(EntladungsTyp));
	bereichDataGridViewTextBoxColumn.DisplayMember = "Value";
	bereichDataGridViewTextBoxColumn.ValueMember = "Key";
}

Wichtiger Hinweis

Ich verwende diese Klasse bereits seit mehreren Jahren und weiß nicht mehr genau ob ich von irgend jemand etwas übernommen und überarbeitet habe, oder ob ich das im stillen Kämmerchen ausgebrütet habe.
Eine kurze Recherche im Internet hat keine direkten Ergebnisse / Quellen hervorgebracht. Es gibt zwar einige Beiträge die sich auch mit enum Helper Klassen beschäftigen, aber die, welche ich gerade gesehen habe, beschäftigen sich nicht genau mit dem von mir hier beschriebenen Thema, so dass ich zur Zeit keine Angaben über eventuelle Quellen, die mich inspiriert haben könnten, machen kann.

Aber wenn jemand erkennt dass ich Code von wem auch immer verwendet habe, hinterlasst dass bitte in einem Kommentar, so dass sich eventuell fehlende Quellnachweise schließen.

11 Gedanken zu „Enum als Datasource für DataGridViewComboBoxColumn im DataGridView verwenden“

  1. Habe mit dem Problem auch rumgekämpft. Unten ist meine Variante.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    /// 
    /// Macht aus einer Enum-Aufzählung eine Datenquelle (typisierte Liste)
    /// mit Objekten vom Typ KeyValuePair(string Key, int Value)
    /// Die Liste ist nach Key mittels LINQ sortiert
    ///
    /// Verwendungsbeispiel (ENUM_NAME muss ersetzt werden !) 
    /// comboBox1.DisplayMember = "Key";
    /// comboBox1.ValueMember = "Value";
    /// comboBox1.DataSource = new EnumDataSource();
    /// 
    /// Text auslesen:
    /// string EnumText = comboBox1.Text;
    /// 
    /// Wert auslesen:
    /// int EnumValue = comboBox1.SelectedValue;
    /// 
    ///  Name einer Enum-Aufzählung
    
    public class EnumDataSource : List<KeyValuePair>
    {
        public EnumDataSource()
            : base()
        {
            var array = new List<KeyValuePair>();
            foreach (var item in Enum.GetValues(typeof(T)))
                array.Add(new KeyValuePair(item.ToString(), (int)item));
    
            this.AddRange(from item in array orderby item.Key select item);
        }
    } 
    

    Beim Verwenden in einer DataGridViewComboBoxColumn
    sollte man drauf achten, das die GridView-Spalte den Int32 (=int) Typ hat.
    Sonst kommt der Fehler „….Cell Wert ist ungültig“ oder so.
    Dieser Fehler kommt auch dann, wenn in der GridView-Spalte ein
    Wert gespeichert ist, der in der Enum-Auflistung nicht vorkommt.
    Allerdings ist das kein Problem dieser Klasse, sondern von DataGridViewComboBoxColumn. Aus meiner Sicht könnte es M$…
    besser lösen, oder zumindest eine vernünftigere Fehlermeldung ausgeben.

    Schöne Grüße

    1. Ich habe deinen Kommentar zusammengefasst und hoffe dass jetzt alle Spitzen Klammern richtig ausgegeben werden 🙂
      Viele Dank für diese Variante.
      Allerdings setzt diese Variante Linq voraus was erst mit .NET Framework 3.5 implementiert wurde.
      Also überall da, und das gibt es tatsächlich noch öfter als man denkt, wo der entsprechende Framework nicht verfügbar ist und man noch mit FW 2.0 auskommen muss, geht diese Variante leider nicht.
      Viele Grüße

  2. Falls wir schon dabei sind alles richtig zu machen 🙂
    bitte mein vorherigen Eintrag entfernen, da waren
    noch andere Übertragungsfehler. Hier die korrekte Variante
    von „EnumDataSource“, die auch ohne LINQ auskommen kann:

    using System;
    using System.Collections.Generic;
    
    public class EnumDataSource<T> : List<KeyValuePair<string, int>>
    {
        public EnumDataSource()
            : base()
        {
            var array = new List<KeyValuePair<string, int>>();
            foreach (var item in Enum.GetValues(typeof(T)))
                array.Add(new KeyValuePair<string, int>(item.ToString(), (int)item));
            this.AddRange(array);
        }
    } 
    

    Falls man bereits LINQ verwendet, kann man die Einträge
    zusätzlich alphabetisch sortieren. Dazu muss man die Zeile
    this.AddRange(array);
    durch

    this.AddRange(from item in array orderby item.Key select item);

    ersetzen.

    Verwendung:

    public enum MyEnum
    { eins = 1, zwei, drei } 
    // ...
    ComboBox cbo = new ComboBox();
    cbo.DisplayMember = "Key";
    cbo.ValueMember = "Value";
    cbo.DataSource = new EnumDataSource<MyEnum>();
    

    Text kann man jetzt mit ‚cbo.Text‘ auslesen und den Wert mit ‚cbo.SelectedValue‘.
    Das funktioniert auch mit der Klasse DataGridViewComboBoxColumn in einem DataGridView.

    Schöne Grüße
    PK

  3. Schönes Codebeispiel Hans-Peter, danke dafür.
    Das Anwendungsbeispiel könnte für den Fall eines gebundenen DataGridViews in InitDgv() noch um die Eigenschaft DataPropertyName ergänzt werden.
    Angenommen, die DataTable für die DataSource der BindingSource beinhaltet den Entladungstyp im gleichnamigen Feld „Entladungstyp“, muss dieser Feldname dem Combo als DataPropertyName zugewiesen werden, damit bei der Anzeige vorhandener Datensätze der richtige Wert des Combos ausgewählt wird:
    bereichDataGridViewTextBoxColumn.DataPropertyName = „Entladungstyp“;

    Grüssle, Herbert

  4. Prueba con esto, sin necesidad de crear nada XD

    Enum RelacionE

    Uno=1

    Dos=2

    Tres=3

    End Enum

     

     Dim enumvalues = New List(Of RelacionE)([Enum].GetValues(GetType(RelacionE)))
            Dim items = enumvalues.ToDictionary(Function(k) [Enum].GetName(GetType(RelacionE), k))
            Relacion.DataSource = items.ToList
            Relacion.DisplayMember = "Key"
            Relacion.ValueMember = "Value"

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.