如何在datagridview列中显示枚举值
我有这个数据库,不是我的设计,但我必须使用它,它包含一个像这样的表:
id | 名称| 状态| ... ----- + ------------ + ---------- + ------ 1 | 产品1 | 2 | ... 2 | 产品2 | 2 | ... 3 | 产品3 | 3 | ... ...... | ...... | ...... | ...
status属性是指枚举所在的位置
0 =无效 1 =开发 2 =激活 3 =老
当我在只读datagridview中显示它时,我希望用户看到枚举的名称(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事件添加到一个列? 或者是什么 ?
我不会在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中,只隐藏具有枚举的整数表示的列。
由于您说这个DGV是“只读”,您可以将数据表读入一个自定义类型的列表,该列表可以就地执行转换。
你可以摆脱try-catch和你的自定义方法,然后简单地写:
e.Value = ((StatusType)e.Value).ToString();
如果该值未解析,则它将显示为其整数值。 这会加速一些事情。
您可以使用相应列的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(); }
您可以使用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的解决方案,如果那是不可能的,那么你可以想到这一点。
目前我不太明白你对1k物品的意思。
但你要做的就是为自己创建枚举,如:
public enum States { Invalid = 0, [Description("In developement")] Dev, Activ, Old, ... }
在您的格式化事件中,您可以调用此函数
/// /// Gets the string of an DescriptionAttribute of an Enum. /// /// The Enum value for which the description is needed. /// If a DescriptionAttribute is set it return the content of it. /// Otherwise just the raw name as string. 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中自动执行此操作,但这是一项必须完成的工作。 所以这并不难。
在将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";