2010-10-13 19 views
6

mam tę bazę danych, a nie mój projekt, ale mam z nim pracować, że zawiera tabela tak:Jak wyświetlić wartości enum w kolumnie DataGridView

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

Stan odnosi się do wyliczenia gdzie

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

Kiedy wyświetlić to w tylko do odczytu DataGridView, chciałbym użytkownika, aby zobaczyć nazwę wyliczenia (Dev, Activ, ...) lub opis zamiast wartości liczbowej. Datagridview jest związany z datatable, który pochodzi z DAL, ponownie nie z mojego projektu, więc nie mogę naprawdę zmienić datatable. Jedynym sposobem znalazłem jak zrobić to przez słuchanie przypadku datagridview.CellFormating gdzie mogę umieścić ten kod:

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

Działa to dobrze, poza tym, że jeśli mam około 1k (nie tak dużo) lub więcej elementów , to trwa wiecznie ... Czy jest lepszy sposób to zrobić?

--- Edytuj ---
Działa to bez zarzutu, moim problemem jest to, że jeśli w datowalnym katalogu jest więcej niż 1000 wierszy, to trwa to zawsze. Problem polega na tym, że zdarzenie CellFormating jest wywoływane dla każdej kolumny, nawet dla tych, które jej nie potrzebują. Powiedzmy, że wyświetlam 15 kolumn, a tam jest 1000 wierszy, to zdarzenie wywołuje 15 000 czasu ...

Czy istnieje lepszy sposób niż użycie zdarzenia CellFormating? Czy istnieje sposób na dodanie zdarzenia CellFormating do tylko jednej kolumny? Albo co ?

+0

@Oliver, K = tys. 1K = 1000 – Brad

+0

Jeśli opisy stanu są zdefiniowane w osobnej tabeli, możesz dołączyć do tej tabeli i zwrócić opisy jako część danych, które chcesz wyświetlić. Tego rodzaju bazy danych mają na celu, a dziwnym jest, że proponowane rozwiązania polegają na iteracji wyników zwróconych przez bazę danych. Oczywiście ten komentarz staje się dyskusyjny, jeśli wymagane dane nie znajdują się w bazie danych lub nie można ich wstawić samodzielnie. –

+0

nie ... Niestety wartości dla statusu nie są w DB (nie mój projekt) –

Odpowiedz

7

Nie zrobiłbym tego na CellFormatting. Zaatakowałbym samą DataTable. Dodałbym wiersz, który ma typ wyliczenia, i pętlę przez tabelę i dodać wartości. Coś takiego:

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

Następnie, w DataGridView po prostu ukryć kolumnę, która ma całkowitą reprezentację Twojego wyliczenia.

+1

Tak, myślałam o tym, ale moim problemem jest to, że DataTable nie pochodzi ode mnie, a ja boję się tego, co może się zdarzyć później w kodzie jeśli dodać kolumnę ... także, to robi to tak naprawdę przyspieszyć do góry? –

+2

Tak, przyśpieszyłoby to działanie, ponieważ wydarzyłoby się to przed połączeniem, a Ty nie musiałbyś zadzierać ze wszystkimi zdarzeniami formatowania. Możesz spróbować klonować DataTable zanim to zrobisz, w ten sposób oryginalny nie zostanie zawalony. Nadal uważam, że będzie szybciej. Spróbuj. – BFree

+0

Spróbuję tego ... sklonować Datatable, dodać nową kolumnę, zrobić inne formowanie, a następnie związać ją z DGV ... Dzięki –

0

Obecnie nie rozumiem, co masz na myśli z 1k pozycji.

Ale co trzeba zrobić, to po prostu tworzyć enum dla siebie lubię:

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

iw swoim swoje wydarzenie formatowania wywołać tę funkcję

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

ten sposób

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

Wszystko, co musisz zrobić, to sprawdzenie, czy zdefiniowałeś wszystkie wartości wyliczeniowe, które są możliwe i że działasz we właściwej kolumnie.

Jeśli masz 1000 wartości w kolumnie statusu, nic nie pomoże ci zautomatyzować tego w .Net, ale jest to zadanie, które trzeba wykonać raz. Więc nie jest to takie trudne.

+0

Przepraszam, jeśli nie byłam jasna ... Jest tylko 6 różnych statusów, co miałem na myśli wtedy, gdy w datatable jest ponad 1000 kolumn, które stają się naprawdę powolne ... Ponadto, podane przez ciebie rozwiązanie jest tym, co robię obecnie metodą getEnumStringValue, ale chcę wiedzieć, czy istnieje lepszy sposób niż pożarów czarownic zdarzeń formatowanie dla każdej kolumny, a nawet te, które nie wymagają formatowania ... będę edytować mój post, aby rzeczy wyraźniej –

2

Ponieważ mówisz, że DGV jest "tylko do odczytu", możesz odczytać tabelę danych na listę niestandardowego typu, który wykonuje konwersję w miejscu.

można pozbyć try-catch i Twojego niestandardową metodę i po prostu napisać:

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

Jeśli wartość nie analizuje, zostanie on wyświetlony jako wartość całkowitą. To trochę przyspieszy.

+0

Użyłem awnsera BFree, ale z twoim sposobem rzucania wartości, aby pozbyć się try..catch, aby przyspieszyć działanie. Dziękuję za anwser. –

+0

Właśnie zdałem sobie sprawę, że obsada nie była nawet potrzebna. – Tergiver

+0

Ups, potrzebujesz rzutowania, jeśli typ w tabeli danych jest liczbą całkowitą. Potrzebuję więcej kawy. – Tergiver

1

Można użyć zdarzenia RowPostPaint w DataGridView. Możesz zrobić, co następuje.

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

W tej metodzie trzeba sprawdzić dla wartości, które chcesz zaktualizować inaczej to rzuci Cię w nieskończonej pętli do aktualizowania wiersz. Po zaktualizowaniu wartości należy unikać aktualizacji. To rozwiązanie ma zastosowanie tylko wtedy, gdy jest to komórka tylko do odczytu.

Proponuję pójść z rozwiązaniem BFree, jeśli nie jest to możliwe, to możesz o tym pomyśleć.

0

Put to gdzieś przed przypisać DataSource do sieci:

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

Uwaga: musisz utworzyć kolumnę ComboBox – Patrick

1

Można użyć właściwości CellTemplate w odpowiedniej kolumnie. Więc najpierw utworzyć klasę dla szablonu komórek nadrzędnych 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() 
     } 
    } 
} 

następnie przypisać nowe instancje nim do szablonów komórek kolumn. Zauważ, że zmiana nie obowiązuje, dopóki nie odświeżysz siatki i dlatego umieściłem ją w konstruktorze:

public frmGoods() 
{ 
    InitializeComponent(); 
    this.sellingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell(); 
    this.buyingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell(); 
} 
Powiązane problemy