当变量名称仅在运行时已知时,如何将变量名称用作 DataGridView 的列 header?
How do I use variable names as a column header for DataGridView when the variable name is only known during runtime?
前言
不确定这是否重要,但我会解释我的项目的结构。它有三层:
本机 C++:
目的是读取多个文件并执行计算。输出是
双打和向量。
C++/CLI 包装器:
我的本机 C++ 程序和 C# GUI 之间的通信层。它还将我的原生 C++ 向量转换为通用列表。
C#:
该层用于设计 GUI,基本上只是以图表和表格的形式呈现结果。
我的目标
我的目标是使用 class Evaluation
中的参数作为列填充 DataGridView
,并将每个已解析文件的值作为行填充。
到目前为止我所做的是:
创建了 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
object 并将 object 添加到名为 [= 的列表中17=] 类型 List<Evaluation>
之后,我将通过 dataGridView1.DataSource = results;
将 List<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:
如何添加包含温度字符串的列作为 HeaderText?
我能否以某种方式将我的 List<Evaluation>
与我的 List<double>
结合起来并将其用作数据源?我知道你必须制作一个列表,但我真的无法声明任何 class 变量。
在使用 dataGridView1.DataSource = results;
声明数据源后,我是否能够手动插入 TAF 列 + 每个 row/file 的值?
是否有任何其他数据结构我可以用作数据源而不是列表,这可能对我有帮助?
我设法使用 Dictionary<string, object>
和 DataTable
解决了我的问题。我认为,为了使用 class 属性解决我的问题,我必须实施反射以便在 运行 时间内定义属性。
这条路线不需要任何反射。当我第一次 运行 Calculate()
时,TAZ
的温度值就知道了。
这些参数适用于所有剩余文件。
第一步: 我没有将参数存储为 class 属性并将其绑定到 DataGridView
,而是决定使用a 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
/.../
结果:
- 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 做同样的事情...
前言
不确定这是否重要,但我会解释我的项目的结构。它有三层:
本机 C++: 目的是读取多个文件并执行计算。输出是 双打和向量。
C++/CLI 包装器: 我的本机 C++ 程序和 C# GUI 之间的通信层。它还将我的原生 C++ 向量转换为通用列表。
C#: 该层用于设计 GUI,基本上只是以图表和表格的形式呈现结果。
我的目标
我的目标是使用 class Evaluation
中的参数作为列填充 DataGridView
,并将每个已解析文件的值作为行填充。
到目前为止我所做的是:
创建了
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
object 并将 object 添加到名为 [= 的列表中17=] 类型List<Evaluation>
之后,我将通过
dataGridView1.DataSource = results;
将
List<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:
如何添加包含温度字符串的列作为 HeaderText?
我能否以某种方式将我的
List<Evaluation>
与我的List<double>
结合起来并将其用作数据源?我知道你必须制作一个列表,但我真的无法声明任何 class 变量。在使用
dataGridView1.DataSource = results;
声明数据源后,我是否能够手动插入 TAF 列 + 每个 row/file 的值?是否有任何其他数据结构我可以用作数据源而不是列表,这可能对我有帮助?
我设法使用 Dictionary<string, object>
和 DataTable
解决了我的问题。我认为,为了使用 class 属性解决我的问题,我必须实施反射以便在 运行 时间内定义属性。
这条路线不需要任何反射。当我第一次 运行 Calculate()
时,TAZ
的温度值就知道了。
这些参数适用于所有剩余文件。
第一步: 我没有将参数存储为 class 属性并将其绑定到
DataGridView
,而是决定使用aDictionary<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 /.../
结果:
- 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 做同样的事情...