Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display enum values in datagridview column

I have this Database, not of my design but I have to work with it, that contains a table like so :

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

The status property refers to an enum where

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

When I display this in a read-only datagridview, I would like the user to see the name of the enum (Dev, Activ, ...) or a description instead of the numeric value. The datagridview is bound to a datatable that comes from a DAL, again not of my design, so I can't really change the datatable. The only way I found how to do that is by listening to the datagridview.CellFormating event where I put this code:

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

This works fine, except that if I have around 1k (not that much) or more items, it takes forever... Is there a better way to do this ?

---Edit---
This works fine as it is, my problem is that if there are more than 1000 rows in the datatable, it takes for ever. The problem is that the CellFormating event fires for every column, even the ones that don't need it. Let say I display 15 columns and there is 1000 rows, then that event fires 15 000 time...

Is there a better way than using the CellFormating Event ? Or is there a way to add the CellFormating Event to only one Column ? Or what ?

like image 993
Pierre-Olivier Goulet Avatar asked Oct 13 '10 13:10

Pierre-Olivier Goulet


2 Answers

I wouldn't do it on CellFormatting. I would attack the DataTable itself. I would add a row that has the type of the enum, and the loop through the table and add the values. Something like this:

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

Then, in your DataGridView just hide the column that has the integer representation of your enum.

like image 172
BFree Avatar answered Oct 20 '22 03:10

BFree


You can use the CellTemplate property of the respective column. So first create a class for the cell template, overriding 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()
        }
    }
}

then assign new instances of it to the columns' cell templates. Note that the change does not take effect until you refresh the grid and that's why I put it into the constructor:

public frmGoods()
{
    InitializeComponent();
    this.sellingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell();
    this.buyingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell();
}
like image 28
Bolek Avatar answered Oct 20 '22 03:10

Bolek