This commit is contained in:
GukSang.Jin
2026-01-04 18:38:18 +08:00
parent e50e051921
commit cd8b263edc

View File

@@ -452,10 +452,10 @@ namespace WindowsFormsApp6
.GetMethod("RefreshDataGridView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
refreshMethod?.Invoke(form1Instance, null);
}));
System.Diagnostics.Debug.WriteLine($"Form1数据读取成功试样 #{newSampleIndex}");
}
}
System.Diagnostics.Debug.WriteLine($"Form1数据读取成功试样 #{timeRows.Count + 1}");
}
catch (Exception ex)
{
@@ -468,150 +468,106 @@ namespace WindowsFormsApp6
/// PLC地址D420 - 初始重量, D422 - 浸润后重量, D402 - 浸润时间, D406 - 悬挂时间, D310 - 运行速度
/// 信号量M252
/// </summary>
/// <summary>
/// 读取Form2数据 - 每次读取一个试样的数据并累加
/// </summary>
private void ReadForm2Data(byte slaveId)
{
try
{
// 读取初始重量D420开始5个试样
ushort[] initialWeights = _modbusMaster.ReadHoldingRegisters(slaveId, 420, 5);
// 读取浸润后重量D422开始5个试样
ushort[] afterWeights = _modbusMaster.ReadHoldingRegisters(slaveId, 422, 5);
// 读取浸润时间D402开始5个试样
ushort[] soakTimes = _modbusMaster.ReadHoldingRegisters(slaveId, 402, 5);
// 读取悬挂时间D406开始5个试样
ushort[] hangTimes = _modbusMaster.ReadHoldingRegisters(slaveId, 406, 5);
// 读取运行速度D310开始5个试样
ushort[] runSpeeds = _modbusMaster.ReadHoldingRegisters(slaveId, 310, 5);
// 使用反射获取Form2的私有字段
var sampleDataTableField = form2Instance.GetType()
.GetField("sampleDataTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (sampleDataTableField != null)
var currentSampleCountField = form2Instance.GetType()
.GetField("currentSampleCount", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (sampleDataTableField == null || currentSampleCountField == null)
{
DataTable dataTable = sampleDataTableField.GetValue(form2Instance) as DataTable;
if (dataTable != null)
{
dataTable.Clear();
int count = Math.Min(initialWeights.Length, 5);
// 转换数据(假设寄存器值为实际值*100
double[] initialWeightValues = new double[count];
double[] afterWeightValues = new double[count];
for (int i = 0; i < count; i++)
{
initialWeightValues[i] = initialWeights[i] / 100.0;
afterWeightValues[i] = afterWeights[i] / 100.0;
}
// 1. 初始重量行
DataRow initialRow = dataTable.NewRow();
initialRow["序号"] = "初始重量(g)";
for (int i = 0; i < count; i++)
{
initialRow[$"试样{i + 1}"] = initialWeightValues[i];
}
dataTable.Rows.Add(initialRow);
// 2. 浸润后重量行
DataRow afterRow = dataTable.NewRow();
afterRow["序号"] = "浸润后重量(g)";
for (int i = 0; i < count; i++)
{
afterRow[$"试样{i + 1}"] = afterWeightValues[i];
}
dataTable.Rows.Add(afterRow);
// 3. 液体吸收量行 (%)
DataRow absorptionRow = dataTable.NewRow();
absorptionRow["序号"] = "液体吸收量(%)";
double[] absorptions = new double[count];
for (int i = 0; i < count; i++)
{
absorptions[i] = ((afterWeightValues[i] - initialWeightValues[i]) / initialWeightValues[i]) * 100;
absorptionRow[$"试样{i + 1}"] = absorptions[i];
}
dataTable.Rows.Add(absorptionRow);
// 4. 浸润时间行(每个试样独立的浸润时间)
DataRow soakTimeRow = dataTable.NewRow();
soakTimeRow["序号"] = "浸润时间";
for (int i = 0; i < count; i++)
{
soakTimeRow[$"试样{i + 1}"] = $"{soakTimes[i]}s";
}
dataTable.Rows.Add(soakTimeRow);
// 5. 悬挂时间行(每个试样独立的悬挂时间)
DataRow hangTimeRow = dataTable.NewRow();
hangTimeRow["序号"] = "悬挂时间";
for (int i = 0; i < count; i++)
{
hangTimeRow[$"试样{i + 1}"] = $"{hangTimes[i]}s";
}
dataTable.Rows.Add(hangTimeRow);
// 6. 运行速度行(每个试样独立的运行速度)
DataRow runSpeedRow = dataTable.NewRow();
runSpeedRow["序号"] = "运行速度";
for (int i = 0; i < count; i++)
{
runSpeedRow[$"试样{i + 1}"] = $"{runSpeeds[i]}mm/min";
}
dataTable.Rows.Add(runSpeedRow);
// 7. 液体吸收量平均值行
DataRow avgRow = dataTable.NewRow();
avgRow["序号"] = "液体吸收量平均值(%)";
double avgAbsorption = absorptions.Average();
avgRow["试样1"] = avgAbsorption;
for (int i = 2; i <= count; i++)
{
avgRow[$"试样{i}"] = DBNull.Value;
}
dataTable.Rows.Add(avgRow);
// 8. 液体吸收量最大值行
DataRow maxRow = dataTable.NewRow();
maxRow["序号"] = "液体吸收量最大值(%)";
double maxAbsorption = absorptions.Max();
maxRow["试样1"] = maxAbsorption;
for (int i = 2; i <= count; i++)
{
maxRow[$"试样{i}"] = DBNull.Value;
}
dataTable.Rows.Add(maxRow);
// 9. 标准偏差行
DataRow stdDevRow = dataTable.NewRow();
stdDevRow["序号"] = "标准偏差";
double stdDev = CalculateStandardDeviation(absorptions);
stdDevRow["试样1"] = stdDev;
for (int i = 2; i <= count; i++)
{
stdDevRow[$"试样{i}"] = DBNull.Value;
}
dataTable.Rows.Add(stdDevRow);
// 刷新显示
dataTable.AcceptChanges();
this.Invoke(new Action(() =>
{
var refreshMethod = form2Instance.GetType()
.GetMethod("RefreshDataGridView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
refreshMethod?.Invoke(form2Instance, null);
}));
}
System.Diagnostics.Debug.WriteLine("无法获取Form2的私有字段");
return;
}
System.Diagnostics.Debug.WriteLine("Form2数据读取成功");
DataTable dataTable = sampleDataTableField.GetValue(form2Instance) as DataTable;
int currentSampleCount = (int)currentSampleCountField.GetValue(form2Instance);
if (dataTable == null)
{
System.Diagnostics.Debug.WriteLine("DataTable为空");
return;
}
// 读取当前试样的数据每次读取2个字节
// 读取初始重量D4202字节
ushort[] initialWeightReg = _modbusMaster.ReadHoldingRegisters(slaveId, 420, 2);
double initialWeight = ConvertRegistersToDouble(initialWeightReg);
// 读取浸润后重量D4222字节
ushort[] afterWeightReg = _modbusMaster.ReadHoldingRegisters(slaveId, 422, 2);
double afterWeight = ConvertRegistersToDouble(afterWeightReg);
// 读取浸润时间D4022字节
ushort[] soakTimeReg = _modbusMaster.ReadHoldingRegisters(slaveId, 402, 2);
int soakTime = ConvertRegistersToInt(soakTimeReg);
// 读取悬挂时间D4062字节
ushort[] hangTimeReg = _modbusMaster.ReadHoldingRegisters(slaveId, 406, 2);
int hangTime = ConvertRegistersToInt(hangTimeReg);
// 读取运行速度D3102字节
ushort[] runSpeedReg = _modbusMaster.ReadHoldingRegisters(slaveId, 310, 2);
int runSpeed = ConvertRegistersToInt(runSpeedReg);
// 确定当前试样索引(基于现有数据)
int sampleIndex = GetNextSampleIndex(dataTable, currentSampleCount);
if (sampleIndex >= currentSampleCount)
{
// 需要扩展试样数量
currentSampleCount = sampleIndex + 1;
currentSampleCountField.SetValue(form2Instance, currentSampleCount);
// 重新初始化DataTable和DataGridView
this.Invoke(new Action(() =>
{
var setSampleCountMethod = form2Instance.GetType()
.GetMethod("SetSampleCount", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
setSampleCountMethod?.Invoke(form2Instance, new object[] { currentSampleCount });
}));
// 重新获取更新后的DataTable
dataTable = sampleDataTableField.GetValue(form2Instance) as DataTable;
}
// 收集所有试样的数据(包括新读取的)
double[] initialWeights = new double[currentSampleCount];
double[] afterWeights = new double[currentSampleCount];
string[] soakTimes = new string[currentSampleCount];
string[] hangTimes = new string[currentSampleCount];
string[] runSpeeds = new string[currentSampleCount];
// 从现有数据中提取已有试样的数据
ExtractExistingData(dataTable, initialWeights, afterWeights, soakTimes, hangTimes, runSpeeds, sampleIndex);
// 添加新读取的试样数据
initialWeights[sampleIndex] = initialWeight;
afterWeights[sampleIndex] = afterWeight;
soakTimes[sampleIndex] = $"{soakTime}s";
hangTimes[sampleIndex] = $"{hangTime}s";
runSpeeds[sampleIndex] = $"{runSpeed}mm/min";
// 更新显示使用Form2的UpdateDisplay逻辑
UpdateForm2Display(dataTable, initialWeights, afterWeights, soakTimes, hangTimes, runSpeeds, currentSampleCount);
// 刷新界面
this.Invoke(new Action(() =>
{
var refreshMethod = form2Instance.GetType()
.GetMethod("RefreshDataGridView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
refreshMethod?.Invoke(form2Instance, null);
}));
System.Diagnostics.Debug.WriteLine($"Form2数据读取成功 - 试样{sampleIndex + 1}");
}
catch (Exception ex)
{
@@ -619,64 +575,349 @@ namespace WindowsFormsApp6
}
}
/// <summary>
/// 将寄存器数据转换为double假设寄存器值为实际值*100
/// </summary>
private double ConvertRegistersToDouble(ushort[] registers)
{
if (registers == null || registers.Length < 2) return 0.0;
// 组合两个寄存器为32位整数高位在前
uint value = ((uint)registers[0] << 16) | registers[1];
return value / 100.0;
}
/// <summary>
/// 将寄存器数据转换为int
/// </summary>
private int ConvertRegistersToInt(ushort[] registers)
{
if (registers == null || registers.Length < 2) return 0;
// 组合两个寄存器为32位整数高位在前
return (registers[0] << 16) | registers[1];
}
/// <summary>
/// 获取下一个试样索引
/// </summary>
private int GetNextSampleIndex(DataTable dataTable, int currentSampleCount)
{
if (dataTable.Rows.Count == 0) return 0;
// 查找初始重量行
var initialRow = dataTable.AsEnumerable()
.FirstOrDefault(r => r.Field<string>("序号") == "初始重量(g)");
if (initialRow == null) return 0;
// 查找第一个空的试样列
for (int i = 0; i < currentSampleCount; i++)
{
var value = initialRow[$"试样{i + 1}"];
if (value == null || value == DBNull.Value ||
(value is double d && d == 0.0))
{
return i;
}
}
// 所有列都有数据,返回下一个索引
return currentSampleCount;
}
/// <summary>
/// 从现有DataTable中提取已有的试样数据
/// </summary>
private void ExtractExistingData(DataTable dataTable, double[] initialWeights, double[] afterWeights,
string[] soakTimes, string[] hangTimes, string[] runSpeeds, int excludeIndex)
{
if (dataTable.Rows.Count == 0) return;
var initialRow = dataTable.AsEnumerable().FirstOrDefault(r => r.Field<string>("序号") == "初始重量(g)");
var afterRow = dataTable.AsEnumerable().FirstOrDefault(r => r.Field<string>("序号") == "浸润后重量(g)");
var soakRow = dataTable.AsEnumerable().FirstOrDefault(r => r.Field<string>("序号") == "浸润时间");
var hangRow = dataTable.AsEnumerable().FirstOrDefault(r => r.Field<string>("序号") == "悬挂时间");
var speedRow = dataTable.AsEnumerable().FirstOrDefault(r => r.Field<string>("序号") == "运行速度");
for (int i = 0; i < initialWeights.Length; i++)
{
if (i == excludeIndex) continue; // 跳过当前要更新的索引
string colName = $"试样{i + 1}";
if (initialRow != null && initialRow.Table.Columns.Contains(colName))
{
var val = initialRow[colName];
initialWeights[i] = (val != null && val != DBNull.Value) ? Convert.ToDouble(val) : 0.0;
}
if (afterRow != null && afterRow.Table.Columns.Contains(colName))
{
var val = afterRow[colName];
afterWeights[i] = (val != null && val != DBNull.Value) ? Convert.ToDouble(val) : 0.0;
}
if (soakRow != null && soakRow.Table.Columns.Contains(colName))
{
var val = soakRow[colName];
soakTimes[i] = (val != null && val != DBNull.Value) ? val.ToString() : "0s";
}
if (hangRow != null && hangRow.Table.Columns.Contains(colName))
{
var val = hangRow[colName];
hangTimes[i] = (val != null && val != DBNull.Value) ? val.ToString() : "0s";
}
if (speedRow != null && speedRow.Table.Columns.Contains(colName))
{
var val = speedRow[colName];
runSpeeds[i] = (val != null && val != DBNull.Value) ? val.ToString() : "0mm/min";
}
}
}
/// <summary>
/// 更新Form2显示精确匹配GenerateMockData的逻辑
/// </summary>
private void UpdateForm2Display(DataTable dataTable, double[] initialWeights, double[] afterWeights,
string[] soakTimes, string[] hangTimes, string[] runSpeeds, int count)
{
dataTable.Clear();
// 1. 初始重量行
DataRow initialRow = dataTable.NewRow();
initialRow["序号"] = "初始重量(g)";
for (int i = 0; i < count; i++)
{
initialRow[$"试样{i + 1}"] = initialWeights[i];
}
dataTable.Rows.Add(initialRow);
// 2. 浸润后重量行
DataRow afterRow = dataTable.NewRow();
afterRow["序号"] = "浸润后重量(g)";
for (int i = 0; i < count; i++)
{
afterRow[$"试样{i + 1}"] = afterWeights[i];
}
dataTable.Rows.Add(afterRow);
// 3. 液体吸收量行 (%)
DataRow absorptionRow = dataTable.NewRow();
absorptionRow["序号"] = "液体吸收量(%)";
double[] absorptions = new double[count];
for (int i = 0; i < count; i++)
{
if (initialWeights[i] > 0)
{
absorptions[i] = ((afterWeights[i] - initialWeights[i]) / initialWeights[i]) * 100;
}
absorptionRow[$"试样{i + 1}"] = absorptions[i];
}
dataTable.Rows.Add(absorptionRow);
// 4. 浸润时间行
DataRow soakTimeRow = dataTable.NewRow();
soakTimeRow["序号"] = "浸润时间";
for (int i = 0; i < count; i++)
{
soakTimeRow[$"试样{i + 1}"] = soakTimes[i];
}
dataTable.Rows.Add(soakTimeRow);
// 5. 悬挂时间行
DataRow hangTimeRow = dataTable.NewRow();
hangTimeRow["序号"] = "悬挂时间";
for (int i = 0; i < count; i++)
{
hangTimeRow[$"试样{i + 1}"] = hangTimes[i];
}
dataTable.Rows.Add(hangTimeRow);
// 6. 运行速度行
DataRow runSpeedRow = dataTable.NewRow();
runSpeedRow["序号"] = "运行速度";
for (int i = 0; i < count; i++)
{
runSpeedRow[$"试样{i + 1}"] = runSpeeds[i];
}
dataTable.Rows.Add(runSpeedRow);
// 计算有效试样数量(初始重量>0的试样
var validAbsorptions = absorptions.Where((a, idx) => initialWeights[idx] > 0).ToArray();
int validCount = validAbsorptions.Length;
// 7. 液体吸收量平均值行
DataRow avgRow = dataTable.NewRow();
avgRow["序号"] = "液体吸收量平均值(%)";
double avgAbsorption = validCount > 0 ? validAbsorptions.Average() : 0;
avgRow["试样1"] = avgAbsorption;
for (int i = 2; i <= count; i++)
{
avgRow[$"试样{i}"] = DBNull.Value;
}
dataTable.Rows.Add(avgRow);
// 8. 液体吸收量最大值行
DataRow maxRow = dataTable.NewRow();
maxRow["序号"] = "液体吸收量最大值(%)";
double maxAbsorption = validCount > 0 ? validAbsorptions.Max() : 0;
maxRow["试样1"] = maxAbsorption;
for (int i = 2; i <= count; i++)
{
maxRow[$"试样{i}"] = DBNull.Value;
}
dataTable.Rows.Add(maxRow);
// 9. 标准偏差行
DataRow stdDevRow = dataTable.NewRow();
stdDevRow["序号"] = "标准偏差";
double stdDev = validCount > 1 ? CalculateStandardDeviation(validAbsorptions) : 0;
stdDevRow["试样1"] = stdDev;
for (int i = 2; i <= count; i++)
{
stdDevRow[$"试样{i}"] = DBNull.Value;
}
dataTable.Rows.Add(stdDevRow);
dataTable.AcceptChanges();
}
/// <summary>
/// 读取Form3数据液体芯吸速率
/// PLC地址D212 - 吸水时间(s)
/// PLC地址D200 - 吸水时间(s)D454 - 吸芯高度(mm)每次测试读取1个试样各2个字节
/// 信号量M310
/// 每次测试添加一个试样的一次测试数据,试样数量动态增长
/// </summary>
private void ReadForm3Data(byte slaveId)
{
try
{
// 读取吸水时间D212开始5个试样 * 3次测试 = 15个寄存器
ushort[] wickingTimes = _modbusMaster.ReadHoldingRegisters(slaveId, 212, 15);
// 读取吸水时间D2002个字节
ushort[] timeRegisters = _modbusMaster.ReadHoldingRegisters(slaveId, 200, 2);
// 读取吸芯高度D4542个字节
ushort[] heightRegisters = _modbusMaster.ReadHoldingRegisters(slaveId, 454, 2);
// 使用反射获取Form3的私有字段
var sampleDataTableField = form3Instance.GetType()
.GetField("sampleDataTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (sampleDataTableField != null)
var currentSampleCountField = form3Instance.GetType()
.GetField("currentSampleCount", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var isVerticalLayoutField = form3Instance.GetType()
.GetField("isVerticalLayout", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (sampleDataTableField == null || currentSampleCountField == null || isVerticalLayoutField == null)
{
DataTable dataTable = sampleDataTableField.GetValue(form3Instance) as DataTable;
System.Diagnostics.Debug.WriteLine("无法获取Form3的私有字段");
return;
}
DataTable dataTable = sampleDataTableField.GetValue(form3Instance) as DataTable;
int currentSampleCount = (int)currentSampleCountField.GetValue(form3Instance);
bool isVerticalLayout = (bool)isVerticalLayoutField.GetValue(form3Instance);
if (dataTable == null || dataTable.Rows.Count == 0)
{
System.Diagnostics.Debug.WriteLine("DataTable为空或没有行");
return;
}
// 将寄存器值转换为实际数据
double wickingTime = ConvertRegistersToDouble(timeRegisters); // 吸水时间(秒)
double wickingHeight = ConvertRegistersToDouble(heightRegisters); // 吸芯高度mm
// 确定当前要填充的位置(试样索引和测试次数)
var position = GetNextForm3Position(dataTable, currentSampleCount, isVerticalLayout);
int sampleIndex = position.Item1; // 试样索引1-based
int testIndex = position.Item2; // 测试次数1-3
// 如果需要扩展试样数量
if (sampleIndex > currentSampleCount)
{
currentSampleCount = sampleIndex;
currentSampleCountField.SetValue(form3Instance, currentSampleCount);
if (dataTable != null && dataTable.Rows.Count > 0)
// 重新初始化DataTable和DataGridView
this.Invoke(new Action(() =>
{
var setSampleCountMethod = form3Instance.GetType()
.GetMethod("SetSampleCount", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
setSampleCountMethod?.Invoke(form3Instance, new object[] { currentSampleCount });
}));
// 重新获取更新后的DataTable
dataTable = sampleDataTableField.GetValue(form3Instance) as DataTable;
}
// 根据布局方式填充数据精确参考GenerateMockData的方式
if (isVerticalLayout)
{
// 纵向布局第1行是吸水时间第2行是吸芯高度
if (dataTable.Rows.Count >= 2)
{
// 获取第一行(吸水时间行)
DataRow timeRow = dataTable.Rows[0];
DataRow heightRow = dataTable.Rows[1];
string columnName = $"试样{sampleIndex}_{testIndex}";
// 填充吸水时间数据(假设寄存器值为实际时间*10
int registerIndex = 0;
for (int i = 1; i <= 5; i++)
// 填充吸水时间
if (timeRow.Table.Columns.Contains(columnName))
{
if (registerIndex < wickingTimes.Length)
{
timeRow[$"试样{i}_1"] = wickingTimes[registerIndex++] / 10.0;
}
if (registerIndex < wickingTimes.Length)
{
timeRow[$"试样{i}_2"] = wickingTimes[registerIndex++] / 10.0;
}
if (registerIndex < wickingTimes.Length)
{
timeRow[$"试样{i}_3"] = wickingTimes[registerIndex++] / 10.0;
}
timeRow[columnName] = wickingTime;
}
// 调用Form3的计算方法
this.Invoke(new Action(() =>
// 填充吸芯高度
if (heightRow.Table.Columns.Contains(columnName))
{
var calculateMethod = form3Instance.GetType()
.GetMethod("CalculateAllRows", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
calculateMethod?.Invoke(form3Instance, null);
var refreshMethod = form3Instance.GetType()
.GetMethod("RefreshDataGridView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
refreshMethod?.Invoke(form3Instance, null);
}));
heightRow[columnName] = wickingHeight;
}
}
}
else
{
// 横向布局:每行是一个试样的一次测试
// 计算行索引:(sampleIndex-1) * 3 + (testIndex-1)
int rowIndex = (sampleIndex - 1) * 3 + (testIndex - 1);
if (rowIndex < dataTable.Rows.Count)
{
DataRow row = dataTable.Rows[rowIndex];
string rowName = $"试样{sampleIndex}_{testIndex}";
// 确保序号正确
row["序号"] = rowName;
// 填充吸水时间列
if (row.Table.Columns.Contains("吸水时间(s)"))
{
row["吸水时间(s)"] = wickingTime;
}
// 填充吸芯高度列
if (row.Table.Columns.Contains("吸芯高度(mm)"))
{
row["吸芯高度(mm)"] = wickingHeight;
}
}
}
System.Diagnostics.Debug.WriteLine("Form3数据读取成功");
// 调用Form3的计算方法计算芯吸速率、平均值、标准偏差
this.Invoke(new Action(() =>
{
var calculateMethod = form3Instance.GetType()
.GetMethod("CalculateAllRows", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
calculateMethod?.Invoke(form3Instance, null);
var refreshMethod = form3Instance.GetType()
.GetMethod("RefreshDataGridView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
refreshMethod?.Invoke(form3Instance, null);
}));
System.Diagnostics.Debug.WriteLine($"Form3数据读取成功 - 试样{sampleIndex}第{testIndex}次测试,吸水时间:{wickingTime:F2}秒,吸芯高度:{wickingHeight:F2}mm");
}
catch (Exception ex)
{
@@ -684,6 +925,75 @@ namespace WindowsFormsApp6
}
}
/// <summary>
/// 获取Form3下一个要填充的位置试样索引和测试次数
/// 返回:(试样索引, 测试次数) - 都是1-based
/// </summary>
private Tuple<int, int> GetNextForm3Position(DataTable dataTable, int currentSampleCount, bool isVerticalLayout)
{
if (isVerticalLayout)
{
// 纵向布局第1行是吸水时间行
if (dataTable.Rows.Count > 0)
{
DataRow timeRow = dataTable.Rows[0];
// 遍历所有试样的所有测试次数,找到第一个空位
for (int i = 1; i <= currentSampleCount; i++)
{
for (int j = 1; j <= 3; j++)
{
string columnName = $"试样{i}_{j}";
if (timeRow.Table.Columns.Contains(columnName))
{
var value = timeRow[columnName];
if (value == null || value == DBNull.Value ||
(value is double d && Math.Abs(d) < 0.001))
{
return Tuple.Create(i, j);
}
}
}
}
// 所有位置都已填充返回下一个试样的第1次测试
return Tuple.Create(currentSampleCount + 1, 1);
}
}
else
{
// 横向布局:每行是一个试样的一次测试
for (int i = 1; i <= currentSampleCount; i++)
{
for (int j = 1; j <= 3; j++)
{
int rowIndex = (i - 1) * 3 + (j - 1);
if (rowIndex < dataTable.Rows.Count)
{
DataRow row = dataTable.Rows[rowIndex];
if (row.Table.Columns.Contains("吸水时间(s)"))
{
var value = row["吸水时间(s)"];
if (value == null || value == DBNull.Value ||
(value is double d && Math.Abs(d) < 0.001))
{
return Tuple.Create(i, j);
}
}
}
}
}
// 所有位置都已填充返回下一个试样的第1次测试
return Tuple.Create(currentSampleCount + 1, 1);
}
// 默认返回第1个试样的第1次测试
return Tuple.Create(1, 1);
}
/// <summary>
/// 计算标准偏差
/// </summary>