Как отобразить значения перечисления в столбце таблицы данных - PullRequest
6 голосов
/ 13 октября 2010

У меня есть эта база данных, не моего дизайна, но я должен работать с ней, которая содержит следующую таблицу:

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

Свойство status ссылается на перечисление, где

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

Когда я отображаю это в виде таблицы только для чтения, я бы хотел, чтобы пользователь видел имя перечисления (Dev, Activ, ...) или описание вместо числового значения. Сетка данных связана с таблицей данных, полученной из 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 только в один столбец? Или что?

Ответы [ 6 ]

7 голосов
/ 13 октября 2010

Я бы не стал делать это на 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 просто спрячьте столбец, который имеет целочисленное представление вашего перечисления.

2 голосов
/ 24 августа 2012

Вы можете использовать свойство 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();
}
2 голосов
/ 13 октября 2010

Поскольку вы говорите, что этот DGV «только для чтения», вы можете прочитать таблицу данных в список пользовательского типа, который выполняет преобразование на месте.

Вы можете избавиться от попыткипоймайте и ваш пользовательский метод и просто напишите:

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

Если значение не анализируется, оно будет отображаться как его целочисленное значение.Это немного ускорит процесс.

1 голос
/ 13 октября 2010

Вы можете использовать событие RowPostPaint для DataGridView. Вы можете сделать следующее.

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, если это невозможно, тогда вы можете подумать об этом.

0 голосов
/ 23 мая 2012

Поместите это куда-нибудь перед тем, как назначить источник данных для сетки:

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 голосов
/ 13 октября 2010

В настоящее время я не совсем понимаю, что вы имеете в виду с 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, но это работа, которую нужно сделатьодин раз.Так что это не так сложно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...