2010-10-13 7 views
6

ich diese Datenbank haben, nicht von meinem Design, aber ich habe mit ihm zu arbeiten, dass enthält eine Tabelle wie folgt:Wie Enum-Werte in Datagridview Spalte angezeigt werden

 
id | Name  | status | ... 
-----+------------+----------+------ 
1 | Product1 | 2  | ... 
2 | Product2 | 2  | ... 
3 | Product3 | 3  | ... 
... | ...  | ...  | ... 

Die Status Eigenschaft bezieht sich auf eine Enumeration, wo

 
0 = Invalid 
1 = Dev 
2 = Activ 
3 = Old 

Wenn ich diese Anzeige in einem schreibgeschützten Datagridview, würde ich den Benutzer wie den Namen des eNUM (Dev, Activ, ...) oder eine Beschreibung anstelle des numerischen Wert anzuzeigen. Der DatagridView ist an eine Datentabelle gebunden, die von einer DAL kommt, wiederum nicht von meinem Design, so dass ich die Datentabelle nicht wirklich ändern kann. Der einzige Weg, fand ich, wie das zu tun ist, indem auf das datagridview.CellFormating Ereignis hören, wo ich diesen Code setzen:

private void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) 
{ 
    if (e.ColumnIndex == 3) // column of the enum 
    { 
     try 
     { 
      e.Value = getEnumStringValue(e.Value); 
     } 
     catch (Exception ex) 
     { 
      e.Value = ex.Message; 
     } 
    } 
} 

Dies funktioniert gut, außer dass, wenn ich um 1k (nicht viel) oder mehr Einzelteile Es dauert ewig ... Gibt es einen besseren Weg, dies zu tun?

--- Bearbeiten ---
Dies funktioniert gut, wie es ist, mein Problem ist, dass, wenn es mehr als 1000 Zeilen in der Datentabelle gibt, es für immer dauert. Das Problem besteht darin, dass das CellFormating-Ereignis für jede Spalte ausgelöst wird, auch für diejenigen, die sie nicht benötigen. Sagen wir, ich zeige 15 Spalten an, und es gibt 1000 Zeilen, dann löst dieses Ereignis 15.000 Mal aus ...

Gibt es einen besseren Weg als das CellFormating Event? Oder gibt es eine Möglichkeit, das CellFormating-Ereignis nur einer Spalte hinzuzufügen? Oder was ?

+0

@Oliver, K = Tausend; 1K = 1.000 – Brad

+0

Wenn die Statusbeschreibungen in einer separaten Tabelle definiert sind, können Sie der Tabelle beitreten und die Beschreibungen als Teil der Daten zurückgeben, die Sie anzeigen möchten. Dies ist die Art von Dingen, die Datenbanken tun sollen, und ich finde es merkwürdig, dass die vorgeschlagenen Lösungen das Iterieren der von der Datenbank zurückgegebenen Ergebnisse beinhalten. Dieser Kommentar wird natürlich ungültig, wenn die erforderlichen Daten nicht in der Datenbank vorhanden sind oder Sie sie nicht selbst einfügen können. –

+0

nein ... leider sind die Werte für den Status nicht in der DB (nicht mein Design) –

Antwort

7

Ich würde es nicht auf CellFormatting tun. Ich würde die DataTable selbst angreifen. Ich würde eine Zeile hinzufügen, die den Typ der Aufzählung und die Schleife durch die Tabelle enthält, und die Werte hinzufügen. Etwas wie folgt aus:

private void Transform(DataTable table) 
    { 
     table.Columns.Add("EnumValue", typeof(SomeEnum)); 
     foreach (DataRow row in table.Rows) 
     { 
      int value = (int)row[1]; //int representation of enum 
      row[2] = (SomeEnum)value; 
     } 
    } 

Dann in Ihrem Datagridview verstecken nur die Spalte, die Integer-Darstellung Ihrer ENUM hat.

+1

Ja, Ich habe darüber gelehrt, aber mein Problem ist, dass die DataTable nicht von mir kommt, und ich habe Angst davor, was später im Code passieren könnte, wenn ich eine Spalte hinzufüge ... Außerdem würde es so Dinge wirklich beschleunigen hoch? –

+2

Ja, es würde die Dinge beschleunigen, weil dies passieren würde, bevor Sie binden, und Sie müssten sich nicht mit allen Formatierungsereignissen herumschlagen. Sie können versuchen, das DataTable zu klonen, bevor Sie das tun, auf diese Weise wird das ursprüngliche nicht durcheinandergebracht. Ich denke immer noch, es wäre schneller. Versuch es einmal. – BFree

+0

Ich werde das versuchen ... klonen Sie das Datatable, fügen Sie eine neue Spalte hinzu, tun Sie jede andere Formatierung, und binden Sie es dann an die DGV ... Danke –

0

Derzeit verstehe ich nicht ganz, was Sie mit 1k Artikel meinen.

Aber was müssen Sie erstellen, wird nicht nur die Enum für sich selbst mag:

public enum States 
{ 
    Invalid = 0, 
    [Description("In developement")] 
    Dev, 
    Activ, 
    Old, 
    ... 
} 

Und in Ihrem Formatierungen Veranstaltung rufen Sie diese Funktion

/// <summary> 
/// Gets the string of an DescriptionAttribute of an Enum. 
/// </summary> 
/// <param name="value">The Enum value for which the description is needed.</param> 
/// <returns>If a DescriptionAttribute is set it return the content of it. 
/// Otherwise just the raw name as string.</returns> 
public static string Description(this Enum value) 
{ 
    if (value == null) 
    { 
     throw new ArgumentNullException("value"); 
    } 

    string description = value.ToString(); 
    FieldInfo fieldInfo = value.GetType().GetField(description); 
    DescriptionAttribute[] attributes = 
     (DescriptionAttribute[]) 
    fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

    if (attributes != null && attributes.Length > 0) 
    { 
     description = attributes[0].Description; 
    } 

    return description; 
} 

auf diese Weise

e.Value = Enum.GetName(typeof(States), e.Value).Description; 

Alles, was Sie tun müssen, ist zu überprüfen, dass Sie alle Enum-Werte definiert haben, die möglich sind und dass yo Sie arbeiten auf der richtigen Spalte.

Wenn Sie 1000 Werte in Ihrer Statusspalte haben, kann Ihnen nichts helfen, dies in .Net zu automatisieren, aber es ist ein Job, der einmal erledigt werden muss. Also ist es nicht so schwer.

+0

Sorry, wenn ich nicht klar war ... Es gibt nur 6 verschiedene Status, was ich meinte war, wenn es über 1000 Spalten in der Datentabelle gibt, wird es wirklich langsam ... Auch die Lösung, die du zur Verfügung stellst, ist die, die ich gerade mache mit der Methode getEnumStringValue, aber ich möchte wissen, ob es einen besseren Weg gibt als das Formatierungsereignis, das für jede Spalte ausgelöst wird, auch diejenigen, die keine Formatierung benötigen ... Ich werde meinen Beitrag bearbeiten, um die Dinge klarer zu machen –

2

Da Sie sagen, dass DGV "schreibgeschützt" ist, könnten Sie die Datentabelle in eine Liste eines benutzerdefinierten Typs einlesen, der die Konvertierung direkt ausführt.

Sie können den Try-Catch und Ihre eigene Methode loszuwerden und einfach schreiben:

e.Value = ((StatusType)e.Value).ToString(); 

Wenn der Wert analysiert nicht, wird es als Integer-Wert angezeigt werden. Das wird die Dinge ein wenig beschleunigen.

+0

Ich benutzte BFree's Awnser aber mit Ihrer Art, den Wert zu werfen, um loszuwerden der Versuch ..., um die Dinge zu beschleunigen. Danke für deine Antwort –

+0

Ich habe gerade festgestellt, dass die Besetzung nicht einmal benötigt wurde. – Tergiver

+0

Hoppla, Sie brauchen die Umwandlung, wenn der Typ in der Datentabelle eine Ganzzahl ist. Ich brauche mehr Kaffee. – Tergiver

1

Sie können das RowPostPaint-Ereignis von DataGridView verwenden. Sie können Folgendes tun.

private void TestGridView_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) 
    { 
     if(e.RowIndex == -1) return; 
     TestGridView[YourColumnIndex, e.RowIndex].Value = YourEnumValue; // You can get your enum string value here. 
    } 

Bei diesem Verfahren Sie für den Wert, den Sie diese aktualisieren möchten zu überprüfen, müssen Sie sonst in Endlosschleife werfen, um die Zeile zu aktualisieren. Sobald der Wert aktualisiert ist, sollten Sie es vermeiden, ihn erneut zu aktualisieren. Diese Lösung ist nur anwendbar, wenn es sich um eine Nur-Lese-Zelle handelt.

Ich würde vorschlagen, mit BFree-Lösung zu gehen, wenn das nicht möglich ist, dann können Sie daran denken.

0

diese irgendwo setzen, bevor Sie die Datasource an das Netz zuweisen:

DataTable stypes = new DataTable(); 
stypes.Columns.Add("id", typeof(short)); 
stypes.Columns.Add("name", typeof(string)); 
DataRow stype; 
string[] ntypes = new string[] { "Invalid", "Dev", "Activ", "Old" }; 
for(int i = 0; i < ntypes.Length; ++i) { 
    stype = stypes.NewRow(); 
    stype["id"] = i; 
    stype["name"] = ntypes[i]; 
    stypes.Rows.Add(stype); 
} 
colStatus.DataSource = stypes; 
colStatus.DisplayMember = "name"; 
colStatus.ValueMember = "id"; 
+0

Hinweis: Sie müssen es zu einer ComboBox-Spalte machen – Patrick

1

Sie können die Celltemplate-Eigenschaft der jeweiligen Spalte. So wird zuerst eine Klasse für die Zelle Vorlage erstellen, überschreiben GetFormattedValue

public class VATGridViewTextBoxCell : DataGridViewTextBoxCell 
{ 
    protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) 
    { 
     Price.VATRateEnum r = (Price.VATRateEnum)(int)value; 
     switch (r) 
     { 
      case Price.VATRateEnum.None: return "0%"; 
      case Price.VATRateEnum.Low: return "14%"; 
      case Price.VATRateEnum.Standard: return "20%"; 
      default: 
       throw new NotImplementedException() 
     } 
    } 
} 

dann neue Instanzen zuweisen, um die Zellvorlagen Spalten. Beachten Sie, dass die Änderung nicht wirksam dauert, bis Sie das Gitter neu geladen und deshalb habe ich es in den Konstruktor setzen:

public frmGoods() 
{ 
    InitializeComponent(); 
    this.sellingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell(); 
    this.buyingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell(); 
} 
Verwandte Themen