2010-10-13 19 views
6

ho questa base di dati, non di mio progetto, ma devo lavorare con esso, che contiene una tabella in questo modo:Come visualizzare i valori enum nella colonna datagridview

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

Lo stato si riferisce ad un enum in cui

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

Quando visualizzo questo in un datagridview sola lettura, desidero all'utente di vedere il nome della enum (Dev, Activ, ...) o una descrizione al posto del valore numerico. Il datagridview è associato a un datatable che proviene da un DAL, non ancora del mio design, quindi non posso davvero cambiare il datatable. L'unico modo che ho trovato il modo per farlo è quello ascoltando l'evento datagridview.CellFormating dove ho messo questo codice:

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; 
     } 
    } 
} 

Questo funziona bene, tranne che se ho intorno 1k (non più di tanto) o più elementi , ci vuole sempre ... C'è un modo migliore per farlo?

--- Modifica ---
Questo funziona bene così com'è, il mio problema è che se ci sono più di 1000 righe nel datatable, ci vuole per sempre. Il problema è che l'evento CellFormating si attiva per ogni colonna, anche per quelle che non ne hanno bisogno. Diciamo che visualizzo 15 colonne e ci sono 1000 righe, quindi quell'evento genera 15.000 volte ...

Esiste un modo migliore rispetto all'utilizzo dell'evento CellFormating? O c'è un modo per aggiungere l'evento CellFormating a una sola colonna? O cosa ?

+0

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

+0

Se le descrizioni dello stato sono definite in una tabella separata, è possibile unirsi a tale tabella e restituire le descrizioni come parte dei dati che si intende visualizzare. Questo è il genere di cose che i database devono fare, e trovo strano che le soluzioni proposte implichino iterare sui risultati restituiti dal database. Ovviamente questo commento diventa discutibile se i dati richiesti non sono nel database o non è possibile inserirli da soli. –

+0

no ... purtroppo i valori per lo stato non sono nel DB (non nella mia progettazione) –

risposta

7

Non lo farei su CellFormatting. Vorrei attaccare il DataTable stesso. Vorrei aggiungere una riga che ha il tipo di enum e il ciclo attraverso la tabella e aggiungere i valori. Qualcosa di simile a questo:

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; 
     } 
    } 

Poi, nel vostro DataGridView solo nascondere la colonna che ha la rappresentazione intera della vostra enum.

+1

Sì, Ho pensato a questo, ma il mio problema è che il DataTable non viene da me, e ho paura di cosa potrebbe accadere più avanti nel codice se aggiungo una colonna ... Inoltre, faremolo in questo modo accelera davvero le cose su ? –

+2

Sì, accelererebbe le cose perché ciò accadrebbe prima di legare e non avresti bisogno di fare confusione con tutti gli eventi di formattazione. Puoi provare a clonare DataTable prima di farlo, in questo modo quello originale non si incasina. Penso ancora che sarebbe più veloce. Dagli Un colpo. – BFree

+0

Proverò a farlo ... clonare il Datatable, aggiungere una nuova colonna, fare altre formazioni e quindi associarlo al DGV ... Grazie –

0

Attualmente non capisco cosa intendi con 1k articoli.

Ma quello che devi fare è semplicemente creare l'enum per te piace:

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

E nel tuo vostro evento formattazione si chiama questa funzione

/// <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; 
} 

quel modo

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

Tutto quello che devi fare è controllare che tu abbia definito tutti i valori enum possibili e che tu stai operando sulla colonna corretta.

Se nella colonna di stato sono presenti 1000 valori, non c'è nulla che possa aiutarti a automatizzare questo in .Net, ma è un lavoro che deve essere svolto una sola volta. Quindi non è così difficile.

+0

Scusate se non ero chiaro ... C'è solo 6 diversi stati, cosa volevo dire quando ci sono oltre 1000 colonne nel datatable che diventano veramente lente ... Inoltre, la soluzione che avete fornito è ciò che sto facendo attualmente con il metodo getEnumStringValue, ma voglio sapere se c'è un modo migliore dell'evento di formattazione che la strega spara per ogni colonna, anche quelli che non hanno bisogno di formattare ... Modificherò il mio post per rendere le cose più chiare –

2

Poiché si dice che questo DGV è "di sola lettura", è possibile leggere la tabella di dati in un elenco di un tipo personalizzato che esegue la conversione sul posto.

Si può sbarazzarsi del try-catch e il metodo personalizzato e semplicemente scrivere:

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

Se il valore non analizza, esso verrà visualizzato come valore intero. Ciò velocizzerà un po 'le cose.

+0

Ho usato l'awnser di BFree ma con il tuo modo di lanciare il valore per sbarazzarti di il try..atch per velocizzare le cose. Grazie per il tuo anser –

+0

Ho appena realizzato che il cast non era nemmeno necessario. – Tergiver

+0

Oops, hai bisogno del cast se il tipo nella tabella dati è intero. Ho bisogno di più caffè. – Tergiver

1

È possibile utilizzare l'evento RowPostPaint di DataGridView. Puoi fare come segue.

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. 
    } 

In questo metodo è necessario controllare il valore che si desidera aggiornare altrimenti questo vi gettarti in ciclo infinito per l'aggiornamento della riga. Una volta aggiornato il valore, è necessario evitare di aggiornarlo di nuovo. Questa soluzione è applicabile solo se si tratta di una cella di sola lettura.

Vorrei suggerire di andare con la soluzione di BFree, se questo non è possibile, allora puoi pensare a questo.

0

mettere questo da qualche parte prima di assegnare il DataSource alla griglia:

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

Nota: dovrai creare una colonna ComboBox – Patrick

1

È possibile utilizzare la proprietà CellTemplate della rispettiva colonna. Quindi, prima di creare una classe per il modello delle cellule, ignorando 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() 
     } 
    } 
} 

quindi assegnare nuove istanze di esso per i modelli di cella delle colonne. Si noti che la modifica non ha effetto finché non si aggiorna la griglia ed è per questo che l'ho inserita nel costruttore:

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