ERROR : Input String was not in a correct format when calculating multiple columns in DATAGRIDVIEW
ERROR : Input String was not in a correct format when calculating multiple columns in DATAGRIDVIEW
我想计算DATAGRIDVIEW中3个单元格的值
计算:
SDI = ((结果 - 平均值) / SD)
我尝试了以下代码:
private void dgvResult_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
string result = dgvResult.CurrentRow.Cells[5].Value.ToString();
string mean = dgvResult.CurrentRow.Cells[6].Value.ToString();
string sd = dgvResult.CurrentRow.Cells[7].Value.ToString();
dgvResult.CurrentRow.Cells[16].Value = (Convert.ToDecimal(result) - Convert.ToDecimal(mean)) ;
// dgvResult.CurrentRow.Cells[8].Value = (Convert.ToDecimal(dgvResult.CurrentRow.Cells[16].Value.ToString()) / Convert.ToDecimal(sd));
}
这行代码工作正确并计算第一部分:
dgvResult.CurrentRow.Cells[16].Value = (Convert.ToDecimal(result) - Convert.ToDecimal(mean)) ;
result - mean
但是添加最后一行代码时出现错误
当在平均单元格中输入数字时出现错误
但是当我删除最后一行代码并在均值字段中键入数字时,它会计算值
dgvResult.CurrentRow.Cells[8].Value = (Convert.ToDecimal(dgvResult.CurrentRow.Cells[16].Value.ToString()) / Convert.ToDecimal(sd));
请问如何解决这个错误?
我在单击按钮时使用搜索按钮填充了网格中的数据
这是代码:
private void btnSearch_Click(object sender, EventArgs e)
{
string sql = @" SELECT samples.name as 'Sample No',
[program_id] as 'Program',
RESULTS.TESTID,
testname as 'Test',
TestsUnits.UnitName as 'Unit',
results.RESULT as 'Result',
RESULTS.mean as 'Mean',
RESULTS.sd as 'Standard Deviation',
RESULTS.sdi as 'Standard Deviation Index',
results.low_limit as 'Low Limit' ,
RESULTS.high_limit as 'High Limit' ,
RESULTS.perf_id as 'Performance',
results.APPROVED_DATE as 'Result Date',
Machines.Machine_name,
results.[Machine_id],
sys_users.user_full_name,
'' as 'RM'
FROM [dbo].[RESULTS]
inner join labtests on RESULTS.testid = labtests.testid
inner join machines on RESULTS.Machine_id = Machines.Machine_id
inner join TestsUnits on labtests.UnitId = TestsUnits.UnitId
inner join sys_users on results.custid = sys_users.user_id
inner join samples on results.sample_id = samples.id
where 1=1 ";
string condition = "";
DateTime fromDate;
DateTime toDate;
if (!DateTime.TryParse(dtFromDate.Value.ToString(), out fromDate))
{
System.Windows.Forms.MessageBox.Show("Invalid From Date");
}
else if (!DateTime.TryParse(dtToDate.Value.ToString(), out toDate))
{
System.Windows.Forms.MessageBox.Show("Invalid to Date");
}
else
{
condition += " and cast(results.APPROVED_DATE as date) between '" + fromDate + "' and '" + toDate + "'";
}
if (textCustId.Text != "")
{
condition += " and RESULTS.custid = '" + textCustId.Text + "'";
}
if (comboProgram.Text != "")
{
condition += " and results.program_id = '" + comboProgram.SelectedValue + "'";
}
DataTable dt = data.fireDatatable(string.Format(sql + condition));
dgvResult.DataSource = dt;
dgvResult.Refresh();
// dgvResult.DataSource = test.GET_RESULTS(Convert.ToInt32(comboProgram.SelectedValue),Convert.ToDateTime(dtFromDate.Text.ToString()),Convert.ToInt32(textCustId.Text));
dgvResult.Columns["Performance"].DefaultCellStyle.NullValue = "1";
// dgvResult.Columns["Standard Deviation"].DefaultCellStyle.NullValue = "1";
// dgvResult.Columns["Mean"].DefaultCellStyle.NullValue = "1";
// dgvResult.Columns["RM"].DefaultCellStyle.NullValue = "1";
}
您应该首先确保您的字符串确实可以转换为十进制。好像sd
不能转成十进制。
要检查这一点,您可以使用 Decimal.TryParse
。即
Decimal n;
(Convert.ToDecimal(dgvResult.CurrentRow.Cells[16].Value.ToString()) / Decimal.TryParse(sd, out n) ? n : 1 /* Default Value */)
还有一件事最好在除法之前检查 sd
,它不应该为零(我已将默认值设置为 1)。
请查看 https://www.educative.io/edpresso/how-to-convert-a-string-to-a-decimal-in-c-sharp,了解有关 Decimal.TryParse
的更多信息。
出现这个错误的原因多种多样,但我建议您:
- 检查函数是否接受输入字符串。
- 即使输入字符串可以转换,您尝试转换的小数可能是 too big or too small,或者精度可能是问题,请检查您是否超出限制。
我还建议使用 Decimal.TryParse,它会使您的代码更耐用。
不清楚网格是如何填充数据的。但是,当您想根据同一行中的其他单元格“计算”网格单元格中的值时,您应该考虑使用 DataTable
和 Expression 列或 Class 将 SDI 值计算为 Class.
的 属性
您可以照原样做,使用网格中的一些事件来“手动”计算值,但是有一种更简单的方法,如上所述。在下面的示例中,我使用了带有表达式列的 DataTable
。这也会将网格列类型设置为 decimals
.
使用您的示例,将有一个 decimal
列用于“结果”、“平均值”和“标准偏差”值。然后我们可以将“表达式”列添加到 DataTable
,它可能看起来像……
dt.Columns.Add("SDI", typeof(decimal), "(Result - Mean) / StandardDeviation");
“表达式”是最后一个参数...
“(结果 - 平均值)/标准偏差”
其中结果是该行结果单元格中的值,这同样适用于其他列名称“平均值”和“标准偏差”。
因为这些列是 decimal
列,我们可以限制值的 conversion/parsing。这里唯一的问题是,如果“StandardDeviation”单元格值为零 (0),则网格将抛出一个明显的 DataError
,因为这将导致除以零的表达式,这显然会失败。所以,我们将不得不寻找这个。
为了提供帮助,我建议我们连接网格 CellValidating
事件。当用户在进行更改后尝试离开单元格时会触发此事件。如果我们查看“StandardDeviation”单元格中的值并检查该值是否为零,那么我们可以弹出一个消息框并注意该单元格中不允许使用零作为值。然后将单元格恢复为原始值并取消编辑。这应该有助于避免可能被零除的情况。
接下来,如果用户开始使用网格 DefaultValuesNeeded
事件在网格的新行(如果可用)中输入内容,我们还可以通过设置一些有效的默认值来帮助用户。
此外,我们还可以连接单元格 KeyPress
事件以仅允许在单元格中输入数字和一个小数点。这将阻止用户在单元格中键入字母字符。注意:即使我们阻止用户“输入”无效字符……用户仍然可以“粘贴”无效值。幸运的是,CellValidating
事件将为我们捕捉到这一点。
设置 KeyPress
事件是使用两个事件完成的。首先是 grids EditingControlShowing
事件。当此事件触发时,单元格将进入“编辑”模式。在这种情况下,我们要做的就是将单元格转换为常规 TextBox
单元格并订阅文本框 KeyPress
事件。当用户在单元格中键入字符时,KeyPress
事件将触发,我们显然会检查并忽略任何无效字符。
下面是上述内容的示例。创建一个新的 winforms 解决方案并将 DataGridView
拖放到表单上以查看实际效果。
DataTable GridDT;
TextBox CurrentEditedCell;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridDT = GetGridDT();
dataGridView1.DataSource = GridDT;
}
private DataTable GetGridDT() {
DataTable dt = new DataTable();
dt.Columns.Add("Result", typeof(decimal));
dt.Columns.Add("Mean", typeof(decimal));
dt.Columns.Add("StandardDeviation", typeof(decimal));
dt.Columns.Add("SDI", typeof(decimal), "(Result - Mean) / StandardDeviation");
dt.Rows.Add(1, 1, 1);
dt.Rows.Add(2, 1, 1);
dt.Rows.Add(3, 1, 1);
dt.Rows.Add(4, 1, 1);
dt.Rows.Add(5, 1, 1);
dt.Rows.Add(6, 1, 1);
return dt;
}
private void dataGridView1_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e) {
e.Row.Cells["Result"].Value = "1";
e.Row.Cells["Mean"].Value = "1";
e.Row.Cells["StandardDeviation"].Value = "1";
}
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "StandardDeviation") {
string userInput = dataGridView1.Rows[e.RowIndex].Cells["StandardDeviation"].EditedFormattedValue.ToString();
if (!decimal.TryParse(userInput, out decimal dValue) || dValue == 0.0M) {
dataGridView1.CancelEdit();
MessageBox.Show("Standard Deviation can not be zero and must be a valid decimal number");
}
}
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "StandardDeviation") {
CurrentEditedCell = (TextBox)e.Control;
if (CurrentEditedCell != null) {
CurrentEditedCell.KeyPress -= new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
CurrentEditedCell.KeyPress += new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
}
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
if (CurrentEditedCell != null) {
CurrentEditedCell.KeyPress -= new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
}
}
private void DecimalNumbersOnlyCell_KeyPress(object sender, KeyPressEventArgs e) {
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.') {
e.Handled = true;
}
if (e.KeyChar == '.' && (sender as TextBox).Text.IndexOf('.') > -1) {
e.Handled = true;
}
}
我希望这有道理并有所帮助。
使用 LINQ
foreach (DataGridViewRow dgvrow in dataGridView1.Rows)
{
//Set the column indexes what you want to sum
double result = ((Convert.ToDouble(dgvrow.Cells[0].Value) - Convert.ToDouble(dgvrow.Cells[1].Value)) / Convert.ToDouble(dgvrow.Cells[2].Value));
dgvrow.Cells.Cast<DataGridViewCell>()
.Select(s => s).ToList<DataGridViewCell>()
.ForEach(f =>
{
if (f.ColumnIndex == 3 && f.Value != null) //column index where to place your sum
{
//have negative results
f.Value = Math.Round(result, 2)
.ToString();
//negative results turn to 0
//f.Value = Math.Round(((result < 0) ? 0 : result), 2)
//.ToString();
}
});
}
有两种结果,有负的和没有的。这取决于你要使用什么。希望对您有所帮助!
我想计算DATAGRIDVIEW中3个单元格的值
计算:
SDI = ((结果 - 平均值) / SD)
我尝试了以下代码:
private void dgvResult_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
string result = dgvResult.CurrentRow.Cells[5].Value.ToString();
string mean = dgvResult.CurrentRow.Cells[6].Value.ToString();
string sd = dgvResult.CurrentRow.Cells[7].Value.ToString();
dgvResult.CurrentRow.Cells[16].Value = (Convert.ToDecimal(result) - Convert.ToDecimal(mean)) ;
// dgvResult.CurrentRow.Cells[8].Value = (Convert.ToDecimal(dgvResult.CurrentRow.Cells[16].Value.ToString()) / Convert.ToDecimal(sd));
}
这行代码工作正确并计算第一部分:
dgvResult.CurrentRow.Cells[16].Value = (Convert.ToDecimal(result) - Convert.ToDecimal(mean)) ;
result - mean
但是添加最后一行代码时出现错误
当在平均单元格中输入数字时出现错误
但是当我删除最后一行代码并在均值字段中键入数字时,它会计算值
dgvResult.CurrentRow.Cells[8].Value = (Convert.ToDecimal(dgvResult.CurrentRow.Cells[16].Value.ToString()) / Convert.ToDecimal(sd));
请问如何解决这个错误?
我在单击按钮时使用搜索按钮填充了网格中的数据 这是代码:
private void btnSearch_Click(object sender, EventArgs e)
{
string sql = @" SELECT samples.name as 'Sample No',
[program_id] as 'Program',
RESULTS.TESTID,
testname as 'Test',
TestsUnits.UnitName as 'Unit',
results.RESULT as 'Result',
RESULTS.mean as 'Mean',
RESULTS.sd as 'Standard Deviation',
RESULTS.sdi as 'Standard Deviation Index',
results.low_limit as 'Low Limit' ,
RESULTS.high_limit as 'High Limit' ,
RESULTS.perf_id as 'Performance',
results.APPROVED_DATE as 'Result Date',
Machines.Machine_name,
results.[Machine_id],
sys_users.user_full_name,
'' as 'RM'
FROM [dbo].[RESULTS]
inner join labtests on RESULTS.testid = labtests.testid
inner join machines on RESULTS.Machine_id = Machines.Machine_id
inner join TestsUnits on labtests.UnitId = TestsUnits.UnitId
inner join sys_users on results.custid = sys_users.user_id
inner join samples on results.sample_id = samples.id
where 1=1 ";
string condition = "";
DateTime fromDate;
DateTime toDate;
if (!DateTime.TryParse(dtFromDate.Value.ToString(), out fromDate))
{
System.Windows.Forms.MessageBox.Show("Invalid From Date");
}
else if (!DateTime.TryParse(dtToDate.Value.ToString(), out toDate))
{
System.Windows.Forms.MessageBox.Show("Invalid to Date");
}
else
{
condition += " and cast(results.APPROVED_DATE as date) between '" + fromDate + "' and '" + toDate + "'";
}
if (textCustId.Text != "")
{
condition += " and RESULTS.custid = '" + textCustId.Text + "'";
}
if (comboProgram.Text != "")
{
condition += " and results.program_id = '" + comboProgram.SelectedValue + "'";
}
DataTable dt = data.fireDatatable(string.Format(sql + condition));
dgvResult.DataSource = dt;
dgvResult.Refresh();
// dgvResult.DataSource = test.GET_RESULTS(Convert.ToInt32(comboProgram.SelectedValue),Convert.ToDateTime(dtFromDate.Text.ToString()),Convert.ToInt32(textCustId.Text));
dgvResult.Columns["Performance"].DefaultCellStyle.NullValue = "1";
// dgvResult.Columns["Standard Deviation"].DefaultCellStyle.NullValue = "1";
// dgvResult.Columns["Mean"].DefaultCellStyle.NullValue = "1";
// dgvResult.Columns["RM"].DefaultCellStyle.NullValue = "1";
}
您应该首先确保您的字符串确实可以转换为十进制。好像sd
不能转成十进制。
要检查这一点,您可以使用 Decimal.TryParse
。即
Decimal n;
(Convert.ToDecimal(dgvResult.CurrentRow.Cells[16].Value.ToString()) / Decimal.TryParse(sd, out n) ? n : 1 /* Default Value */)
还有一件事最好在除法之前检查 sd
,它不应该为零(我已将默认值设置为 1)。
请查看 https://www.educative.io/edpresso/how-to-convert-a-string-to-a-decimal-in-c-sharp,了解有关 Decimal.TryParse
的更多信息。
出现这个错误的原因多种多样,但我建议您:
- 检查函数是否接受输入字符串。
- 即使输入字符串可以转换,您尝试转换的小数可能是 too big or too small,或者精度可能是问题,请检查您是否超出限制。
我还建议使用 Decimal.TryParse,它会使您的代码更耐用。
不清楚网格是如何填充数据的。但是,当您想根据同一行中的其他单元格“计算”网格单元格中的值时,您应该考虑使用 DataTable
和 Expression 列或 Class 将 SDI 值计算为 Class.
您可以照原样做,使用网格中的一些事件来“手动”计算值,但是有一种更简单的方法,如上所述。在下面的示例中,我使用了带有表达式列的 DataTable
。这也会将网格列类型设置为 decimals
.
使用您的示例,将有一个 decimal
列用于“结果”、“平均值”和“标准偏差”值。然后我们可以将“表达式”列添加到 DataTable
,它可能看起来像……
dt.Columns.Add("SDI", typeof(decimal), "(Result - Mean) / StandardDeviation");
“表达式”是最后一个参数... “(结果 - 平均值)/标准偏差”
其中结果是该行结果单元格中的值,这同样适用于其他列名称“平均值”和“标准偏差”。
因为这些列是 decimal
列,我们可以限制值的 conversion/parsing。这里唯一的问题是,如果“StandardDeviation”单元格值为零 (0),则网格将抛出一个明显的 DataError
,因为这将导致除以零的表达式,这显然会失败。所以,我们将不得不寻找这个。
为了提供帮助,我建议我们连接网格 CellValidating
事件。当用户在进行更改后尝试离开单元格时会触发此事件。如果我们查看“StandardDeviation”单元格中的值并检查该值是否为零,那么我们可以弹出一个消息框并注意该单元格中不允许使用零作为值。然后将单元格恢复为原始值并取消编辑。这应该有助于避免可能被零除的情况。
接下来,如果用户开始使用网格 DefaultValuesNeeded
事件在网格的新行(如果可用)中输入内容,我们还可以通过设置一些有效的默认值来帮助用户。
此外,我们还可以连接单元格 KeyPress
事件以仅允许在单元格中输入数字和一个小数点。这将阻止用户在单元格中键入字母字符。注意:即使我们阻止用户“输入”无效字符……用户仍然可以“粘贴”无效值。幸运的是,CellValidating
事件将为我们捕捉到这一点。
设置 KeyPress
事件是使用两个事件完成的。首先是 grids EditingControlShowing
事件。当此事件触发时,单元格将进入“编辑”模式。在这种情况下,我们要做的就是将单元格转换为常规 TextBox
单元格并订阅文本框 KeyPress
事件。当用户在单元格中键入字符时,KeyPress
事件将触发,我们显然会检查并忽略任何无效字符。
下面是上述内容的示例。创建一个新的 winforms 解决方案并将 DataGridView
拖放到表单上以查看实际效果。
DataTable GridDT;
TextBox CurrentEditedCell;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridDT = GetGridDT();
dataGridView1.DataSource = GridDT;
}
private DataTable GetGridDT() {
DataTable dt = new DataTable();
dt.Columns.Add("Result", typeof(decimal));
dt.Columns.Add("Mean", typeof(decimal));
dt.Columns.Add("StandardDeviation", typeof(decimal));
dt.Columns.Add("SDI", typeof(decimal), "(Result - Mean) / StandardDeviation");
dt.Rows.Add(1, 1, 1);
dt.Rows.Add(2, 1, 1);
dt.Rows.Add(3, 1, 1);
dt.Rows.Add(4, 1, 1);
dt.Rows.Add(5, 1, 1);
dt.Rows.Add(6, 1, 1);
return dt;
}
private void dataGridView1_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e) {
e.Row.Cells["Result"].Value = "1";
e.Row.Cells["Mean"].Value = "1";
e.Row.Cells["StandardDeviation"].Value = "1";
}
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "StandardDeviation") {
string userInput = dataGridView1.Rows[e.RowIndex].Cells["StandardDeviation"].EditedFormattedValue.ToString();
if (!decimal.TryParse(userInput, out decimal dValue) || dValue == 0.0M) {
dataGridView1.CancelEdit();
MessageBox.Show("Standard Deviation can not be zero and must be a valid decimal number");
}
}
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "StandardDeviation") {
CurrentEditedCell = (TextBox)e.Control;
if (CurrentEditedCell != null) {
CurrentEditedCell.KeyPress -= new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
CurrentEditedCell.KeyPress += new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
}
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
if (CurrentEditedCell != null) {
CurrentEditedCell.KeyPress -= new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
}
}
private void DecimalNumbersOnlyCell_KeyPress(object sender, KeyPressEventArgs e) {
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.') {
e.Handled = true;
}
if (e.KeyChar == '.' && (sender as TextBox).Text.IndexOf('.') > -1) {
e.Handled = true;
}
}
我希望这有道理并有所帮助。
使用 LINQ
foreach (DataGridViewRow dgvrow in dataGridView1.Rows)
{
//Set the column indexes what you want to sum
double result = ((Convert.ToDouble(dgvrow.Cells[0].Value) - Convert.ToDouble(dgvrow.Cells[1].Value)) / Convert.ToDouble(dgvrow.Cells[2].Value));
dgvrow.Cells.Cast<DataGridViewCell>()
.Select(s => s).ToList<DataGridViewCell>()
.ForEach(f =>
{
if (f.ColumnIndex == 3 && f.Value != null) //column index where to place your sum
{
//have negative results
f.Value = Math.Round(result, 2)
.ToString();
//negative results turn to 0
//f.Value = Math.Round(((result < 0) ? 0 : result), 2)
//.ToString();
}
});
}
有两种结果,有负的和没有的。这取决于你要使用什么。希望对您有所帮助!