Как использовать имена переменных в качестве заголовка столбца для DataGridView, если имя переменной известно только во время выполнения?

Предисловие

Не уверен, что это имеет значение, но я объясню, как устроен мой проект. Он имеет три слоя:

  • родной C++: Цель состоит в том, чтобы прочитать несколько файлов и выполнить вычисления. Выходные данные — двойники и векторы.

  • C++/CLI Wrapper: уровень связи между моей родной программой на C++ и графическим интерфейсом C#. Он также преобразует мои родные векторы C++ в общие списки.

  • C#: этот уровень используется для разработки графического интерфейса и, в основном, просто для представления результатов в виде диаграмм и таблиц.


Моя цель

Моя цель - заполнить DataGridView моими параметрами из class Evaluation в виде столбца и значениями каждого проанализированного файла в виде строки.

Что я сделал до сих пор:

  • Создал class Evaluation с каждым параметром в качестве свойства

    public ref class Evaluation 
    {     
     /.../ constructor exists
    
         System::Collections::Generic::List<double> ^GetTAFValues();
         System::Collections::Generic::List<double> ^GetTAFTemps();
    
         property double parameterA
         {
            double get() { return getParameterA(); }
         }
    
         property double parameterB
         {
            double get() { return getParameterB(); }
         }
     /.../
    }
    
  • Для каждого проанализированного файла (используя цикл foreach) я бы создал новый объект Evaluation и добавил этот объект в список с именем results типа List<Evaluation>.

  • После этого я бы привязал List<Evaluation> к DataGridView, выполнив dataGridView1.DataSource = results;

Пока это работает очень хорошо, но только для параметров A и B. Чего мне не хватает, так это моего параметра TAF.

TAF состоит из температуры и значения. Например:

List<double> TAFValues =  new List<double> {1, 2, 3, 4};
List<double> TAFTemps = new List<double> {-30, -10, 25, 50,};

Что мне нужно, так это добавить столбцы с именами TAF-30, TAF-10, TAF25, TAF50 со значениями, прикрепленными из TAFValue. Эти четыре параметра можно использовать для всех остальных файлов.

Я не могу добавить TAF в качестве свойства, потому что я не знаю, сколько шагов температуры используется во время компиляции и какое имя свойства (читай: какая температура) будет.

Вопросы/идеи:

  • Как добавить столбцы, содержащие строки температуры в качестве заголовка?

  • Могу ли я как-то объединить свой List<Evaluation> с моим List<double> и использовать его как источник данных? Я знаю, что вам нужно будет составить список, но я не могу объявить какие-либо переменные класса.

  • Могу ли я вручную вставить столбцы TAF + значения для каждой строки/файла ПОСЛЕ того, как источник данных был объявлен с dataGridView1.DataSource = results;?

  • Существуют ли какие-либо другие структуры данных, которые я мог бы использовать в качестве источника данных вместо списка, которые могли бы мне помочь?


person Haie    schedule 19.09.2018    source источник
comment
Будут ли все Evaluation иметь одинаковые TAFTemp записи?   -  person Michael    schedule 19.09.2018
comment
Все оценки будут иметь одинаковые температурные шаги и, следовательно, будут использовать одни и те же записи TAF для одного и того же DataGridView, да.   -  person Haie    schedule 20.09.2018


Ответы (2)


Мне удалось решить мою проблему, используя Dictionary<string, object> и DataTable. Я думаю, что для решения моей проблемы с использованием свойств класса мне пришлось бы реализовать отражения, чтобы определять свойства во время выполнения.

Этот маршрут не требует никаких размышлений. Значения температуры для TAZ известны, когда я запускаю Calculate() в первый раз. Параметры применимы ко всем остальным файлам.


  • Первый шаг: вместо того, чтобы хранить мои параметры как свойства класса и привязывать их к DataGridView, я решил использовать Dictionary<string, object> для хранения своих параметров. Поскольку Dictionary хранит string, я смог объявить имена динамических столбцов, выполнив "TAZ" + temperature.ToString() (temperature — это vector<int>).

    // C++/CLI Wrapper file
    using namespace System::Collections::Generic;
    
    Dictionary<String^, Object^>^ EvaluationCLI::GetParameters()
    {
        Dictionary<String^, Object^>^ d = gcnew Dictionary<String^, Object^>();
        List<int>^ temps = GetTAFTemps();
        List<double>^ TAZ = GetTAZValues();
    
        d->Add("Parameter A", GetParameterA());
        d->Add("Parameter B", GetParameterB());
    
        for (int i = 0; i < temps->Count; i++)
        {
            d->Add("TAZ_" + temps[i].ToString(), TAZ[i] );
        }
        return d;
    }
    
  • Второй шаг. Вместо того, чтобы использовать свойства из Evaluation и добавлять их в List<Evaluation>, я бы использовал Dictionary<string, object> и заполнил DataTable как DataSource.

    // C#
    /.../
    var dt = new System.Data.DataTable();
    
        foreach (string path in listBox.Items) // file(paths) are stored in a ListBox
        {
            Evaluation eval = new Evaluation(path); // create Evaluation for that file
    
            eval.Calculate(); // does calculations and stores results inside the native C++ vectors/doubles
            Dictionary<string, object> dict = eval.GetParameters(); // retrieve the parameters from native C++ as a Dictionary
    
            if (table.Columns.Count < 1)  // only add columns when DataTable is empty
            {
                foreach (var c in dict.Keys)
                    table.Columns.Add(new DataColumn(c)); // add new column for each parameter string
            }
    
            DataRow row = table.NewRow();  // create new row for each file
            int i = 0;
    
            foreach (var value in dict.Values)
            {
                row[i] = value; // inserts values column by column
                i++;
            }
            table.Rows.Add(row); // add the populated row to the DataTable
        }
    dataGridView1.DataSource = table; // bind DataTable as a DataSource
    /.../
    

Результаты:

  • DataGridView с именами параметров времени выполнения в виде столбцов
  • Каждая строка представляет новый файл/оценку
  • Значения строк соответствуют столбцам параметров

    |---------------------|------------------|------------------|------------------|
    |     Parameter A     |    Parameter B   |       TAZ_10     |       TAZ_50     |
    |---------------------|------------------|------------------|------------------|
    |          12         |         26       |         96       |         89       |
    |---------------------|------------------|------------------|------------------|
    |          85         |         34       |         91       |         72       |
    |---------------------|------------------|------------------|------------------|
    |         ...         |        ...       |        ...       |        ...       |
    |---------------------|------------------|------------------|------------------|
    
person Haie    schedule 20.09.2018

У меня были те же проблемы, вот мое решение... передача списка имен заголовков

    public void dgv_SetHeaderNames(DataGridView dgv, List<string> colNames, bool withColNum = false)
    {
        foreach (DataGridViewColumn dgvCol in dgv.Columns)
        {
            int currCol = dgvCol.Index;
            string colText = "";
            if (currCol >= colNames.Count)
            {
                // if there are more columns than name we will use the column number, anyway.
                colText = currCol.ToString();
            }
            else
            {
                if (withColNum == true)
                {
                    colText = currCol.ToString() + " - " + colNames[currCol];
                }
                else
                {
                    colText = colNames[currCol];
                }
            }
            dgv.Columns[currCol].HeaderText = colText;
        }
    }

Единственная проблема, с которой я столкнулся, заключается в том, что в VS2017 я получаю IDE0028 для своей инициализации.

Но, как видите, я повторно использую список для нескольких DataGridView в своем проекте...

        List<string> colNames = new List<string>();
        colNames.Add("Desc");
        colNames.Add("Freq");
        colNames.Add("Date");
        colNames.Add("Amount");
        colNames.Add("Pay From");
        dgv_SetHeaderNames(dgvDebits, colNames);
        dgvDebits.ColumnCount = colNames.Count;
        colNames[4] = "Type";
        dgv_SetHeaderNames(dgvIncome, colNames);
        dgvIncome.ColumnCount = colNames.Count;

        colNames.Clear();
        colNames.Add("Key");
        colNames.Add("Description");
        colNames.Add("Date");
        colNames.Add("Freq");
        colNames.Add("Amount");
        colNames.Add("Pay From");
        colNames.Add("USAA Checking");
        colNames.Add("Amazon VISA");
        dgv_SetHeaderNames(dgvWorking, colNames);

Я думаю, что предпочитаю простоту VS2010!

Еще один приятный маленький трюк, который я изучил, - это использование списка для заполнения данной строки...

dgvWorking.Rows.Add(wList.ToArray());

Однако я не нашел примеров, чтобы сделать то же самое с заголовками...

person user3279899    schedule 30.09.2018