2010-10-13 19 views
6

tengo esta base de datos, no de mi diseño, pero tengo que trabajar con él, que contiene una tabla de este modo:cómo mostrar los valores de enumeración en la columna DataGridView

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

El estado se refiere a una enumeración donde

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

Cuando puedo mostrar esto en un DataGridView de sólo lectura, me gustaría que el usuario vea el nombre de la enumeración (Dev, Activ, ...) o una descripción en lugar del valor numérico. El datagridview está vinculado a una tabla de datos que proviene de un DAL, una vez más no de mi diseño, por lo que realmente no puedo cambiar la tabla de datos. La única manera que he encontrado la manera de hacer que está detectando el evento datagridview.CellFormating donde pongo este código:

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

Esto funciona bien, excepto que si tengo alrededor de 1k (no mucho) o más artículos , lleva una eternidad ... ¿Hay una mejor manera de hacer esto?

--- Editar ---
Esto funciona bien tal como es, mi problema es que si hay más de 1000 filas en la tabla de datos, se tarda para siempre. El problema es que el evento CellFormating se activa para cada columna, incluso para las que no la necesitan. Supongamos que muestro 15 columnas y hay 1000 filas, luego ese evento dispara 15 000 veces ...

¿Hay una mejor manera que usar el evento CellFormating? ¿O hay una forma de agregar el evento CellFormating a una sola columna? O que ?

+0

@Oliver, K = thousand; 1K = 1,000 – Brad

+0

Si las descripciones de estado se definen en una tabla separada, entonces puede unirse a esa tabla y devolver las descripciones como parte de los datos que debe mostrar. Este es el tipo de cosas que las bases de datos deben hacer, y me parece extraño que las soluciones propuestas impliquen iterar sobre los resultados devueltos por la base de datos. Por supuesto, este comentario se vuelve irrelevante si los datos requeridos no están en la base de datos o usted no puede insertarlos usted mismo. –

+0

no ... lamentablemente los valores para el estado no están en la base de datos (no es mi diseño) –

Respuesta

7

No lo haría en CellFormatting. Atacaría la DataTable en sí. Agregaría una fila que tenga el tipo de la enumeración y el ciclo a través de la tabla y agregue los valores. Algo como esto:

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

Luego, en su DataGridView simplemente ocultar la columna que tiene la representación entera de que su enumeración.

+1

Sí, Pensé en eso, pero mi problema es que DataTable no viene de mí, y me da miedo lo que podría suceder más adelante en el código si agrego una columna ... Además, hacerlo de esta manera realmente acelera las cosas arriba ? –

+2

Sí, aceleraría las cosas porque esto sucedería antes de vincularse, y no tendría que meterse con todos los eventos de formateo. Puedes intentar clonar DataTable antes de hacer esto, de esa forma el original no se arruina. Sigo pensando que sería más rápido. Dale un tiro. – BFree

+0

Voy a intentar eso ... clonar la tabla de datos, agregar una nueva columna, hacer cualquier otro formateado, y luego vincularlo a la DGV ... Gracias –

0

Actualmente no entiendo exactamente lo que quiere decir con 1k artículos.

Pero lo que tiene que hacer es crear la enumeración por sí mismo gustan:

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

Y en el evento de formato le llama a esta función

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

de esa manera

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

Todo lo que tienes que hacer es verificar que hayas definido todos los valores de enum que son posibles y que estás operando en la columna correcta.

Si tiene 1000 valores en su columna de estado, no hay nada que pueda ayudarlo a automatizar esto en .Net, pero es un trabajo que tiene que hacerse una vez. Entonces no es tan difícil.

+0

Disculpe si no estaba claro ... Solo hay 6 estados diferentes, lo que quise decir es que cuando hay más de 1000 columnas en la tabla de datos se pone realmente lento ... Además, la solución que proporcionó es lo que estoy haciendo actualmente con el método getEnumStringValue, pero quiero saber si hay una forma mejor que el evento de formato que dispara una bruja para cada columna, incluso las que no necesitan formateo ... Editaré mi publicación para aclarar las cosas –

2

Dado que usted dice que este DGV es de "solo lectura", puede leer la tabla de datos en una lista de un tipo personalizado que realiza la conversión in situ.

Usted puede deshacerse de la try-catch y su método personalizado y simplemente escribir:

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

Si el valor no analiza, se mostrará como su valor entero. Eso acelerará un poco las cosas.

+0

Utilicé la herramienta de BFree pero con su forma de emitir el valor para deshacerse de el try..catch para acelerar las cosas. Gracias por su guinda –

+0

Me acabo de dar cuenta de que el yeso ni siquiera era necesario. – Tergiver

+0

Vaya, necesita el elenco si el tipo en la tabla de datos es entero. Necesito más café – Tergiver

1

Puede usar el evento RowPostPaint de DataGridView. Puedes hacer lo siguiente.

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

En este método es necesario comprobar el valor que desee actualizar de lo contrario este será echar en el bucle infinito para actualizar la fila. Una vez que se actualiza el valor, debe evitar actualizarlo nuevamente. Esta solución solo es aplicable si esta es una celda de solo lectura.

Sugeriría ir con la solución de BFree, si eso no es posible, entonces puede pensar en esto.

0

poner esto en algún lugar antes de asignar el origen de datos a la red:

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: tendrás que convertirlo en una columna ComboBox – Patrick

1

Usted puede utilizar la propiedad CellTemplate de la columna respectiva. Así que en primer lugar crear una clase para la plantilla de células, anulando 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() 
     } 
    } 
} 

luego asignar nuevas instancias de la misma a las plantillas de celda de las columnas. Tenga en cuenta que el cambio no tendrá efecto hasta que actualice la cuadrícula y es por eso que lo puse en el constructor:

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