当变量名称仅在运行时已知时,如何将变量名称用作 DataGridView 的列 header?

How do I use variable names as a column header for DataGridView when the variable name is only known during runtime?

前言

不确定这是否重要,但我会解释我的项目的结构。它有三层:


我的目标

我的目标是使用 class Evaluation 中的参数作为列填充 DataGridView,并将每个已解析文件的值作为行填充。

到目前为止我所做的是:

到目前为止效果很好,但仅适用于参数 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 添加为 属性,因为我不知道在编译期间使用了多少温度步长以及 属性 名称(读取:哪个温度)会是。

Questions/Ideas:

我设法使用 Dictionary<string, object>DataTable 解决了我的问题。我认为,为了使用 class 属性解决我的问题,我必须实施反射以便在 运行 时间内定义属性。

这条路线不需要任何反射。当我第一次 运行 Calculate() 时,TAZ 的温度值就知道了。 这些参数适用于所有剩余文件。


  • 第一步: 我没有将参数存储为 class 属性并将其绑定到 DataGridView,而是决定使用a Dictionary<string, object> 来存储我的参数。 由于 Dictionary 存储 string 我可以通过 "TAZ" + temperature.ToString() 声明动态列名(temperaturevector<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
    /.../
    

结果:

  • A DataGridView,运行时间参数名称作为列
  • 每一行代表一个新的file/evaluation
  • 行值匹配参数列

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

我遇到了同样的问题,这是我的解决方案...传递 header 个名称的列表

    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());

虽然我还没有找到任何示例来对 Headers 做同样的事情...