如何在datagridview列中显示枚举值

时间:2010-10-13 13:35:15

标签: c# datagridview enums

我有这个数据库,不是我的设计,但我必须使用它,它包含一个像这样的表:

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

status属性是指枚举

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

当我在只读数据网格视图中显示它时,我希望用户看到枚举的名称(Dev,Activ,...)或描述而不是数值。 datagridview绑定到来自DAL的数据表,同样不属于我的设计,因此我无法真正更改数据表。我发现如何做到这一点的唯一方法是通过监听datagridview.CellFormating事件,我把这段代码放在:

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

这种方法很好,除非我有大约1k(不是那么多)或更多的物品,它需要永远...... 有更好的方法吗?

--- ---编辑
这样可以正常工作,我的问题是,如果数据表中有超过1000行,则需要永远。问题是CellFormating事件会触发每一列,甚至是那些不需要它的列。假设我显示15列并且有1000行,那么该事件会触发15 000次......

有没有比使用CellFormating事件更好的方法?或者有没有办法将CellFormating事件添加到一个列?或者是什么?

7 个答案:

答案 0 :(得分:7)

我不会在CellFormatting上做到这一点。我会攻击DataTable本身。我会添加一个具有枚举类型的行,并通过表循环并添加值。像这样:

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

然后,在DataGridView中只隐藏具有枚举的整数表示的列。

答案 1 :(得分:2)

由于您说这个DGV是“只读”,您可以将数据表读入一个自动执行转换的自定义类型列表。

你可以摆脱try-catch和你的自定义方法,只需写下:

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

如果值未解析,则将显示为其整数值。这会加快速度。

答案 2 :(得分:2)

您可以使用相应列的CellTemplate属性。因此,首先为单元格模板创建一个类,重写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()
        }
    }
}

然后将其新实例分配给列的单元格模板。请注意,在刷新网格之前更改不会生效,这就是我将其放入构造函数的原因:

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

答案 3 :(得分:1)

您可以使用DataGridView的RowPostPaint事件。你可以这样做。

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

在此方法中,您需要检查要更新的值,否则会使您进入无限循环以更新行。更新值后,应避免再次更新。此解决方案仅适用于只读单元格的情况。

我建议使用BFree的解决方案,如果不可能,那么你可以想到这一点。

答案 4 :(得分:0)

目前我不太明白你对 1k项的意思。

但你要做的就是为自己创建枚举,如:

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

在您的格式化事件中,您可以调用此函数

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

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

您所要做的就是检查您是否已经定义了所有可能的枚举值以及您在正确的列上运行。

如果您的状态列中有1000个值,那么在.Net中没有什么可以帮助您自动执行此操作,但这是一项必须完成的工作。所以这并不难。

答案 5 :(得分:0)

在将DataSource分配给网格之前将其放在某处:

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

答案 6 :(得分:0)

(TL;DR) 就个人而言,仅将 GridViewDataTextColumnFieldName="CurrentStatus" 一起使用效果很好(显示枚举名称而不是值)。

我搜索这个是因为我不知道使用什么类型的 GridViewData 来正确显示我的枚举,答案让我得出结论,它比实际更难。