【问题标题】:CurrentCellDirtyStateChanged doesn't work after a datagridview error C#在 datagridview 错误 C# 后 CurrentCellDirtyStateChanged 不起作用
【发布时间】:2017-05-27 04:31:38
【问题描述】:

我有一个datagridview,我从数据库中加载数据。该 datagridview 有 2 个 int 列,我在其中插入数字。而且,如果我在两列之一中插入一个数字,那么还有另外两列单元格会自动填充数学运算的结果。相反,如果我插入一个字母,datagridview 会显示一个错误。

问题是这样的:每当 datagridview 显示错误时,在错误消息框中单击“确定”后,我可以继续编辑单元格,但 CurrentCellDirtyStateChanged 事件不起作用。因此,其他两列单元格不会自动填充。我需要它们在显示错误后自动填充。

这是我的代码:

private void dgvReciboPagoSalario_DataError(object sender, DataGridViewDataErrorEventArgs e)

    {
        e.ThrowException = false;

        string Error = "Error: La columna " +
            dgvReciboPagoSalario.Columns[e.ColumnIndex].HeaderText +
            " es de tipo numérico";

        DialogResult DR= MessageBox.Show(Error, "Error",
            MessageBoxButtons.OK, MessageBoxIcon.Error);

        e.Cancel = false;
    }

这是 CurrentCellDirtyStateChanged 事件:

private void dgvReciboPagoSalario_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {//modificar campos de dgv al mismo tiempo que cambio otro
        int HO = 0;
        int HF = 0;
        long SXH = 0;
        long Subtotal = 0;
        long DeduccionesPrestamo = 0;
        long DeduccionesCCSS = 0;
        long Total = 0;

        if (dgvReciboPagoSalario.IsCurrentCellDirty)
        {


            dgvReciboPagoSalario.CommitEdit(DataGridViewDataErrorContexts.Commit);


            if (!string.IsNullOrEmpty(dgvReciboPagoSalario.CurrentRow.Cells["Horas Ordinarias"].Value.ToString()))
            {
                HO = Convert.ToInt32(dgvReciboPagoSalario.CurrentRow.Cells["Horas Ordinarias"].Value);
            }


            if (!string.IsNullOrEmpty(dgvReciboPagoSalario.CurrentRow.Cells["Horas Feriado"].Value.ToString()))
            {
                HF = Convert.ToInt32(dgvReciboPagoSalario.CurrentRow.Cells["Horas Feriado"].Value);
            }

            SXH = Convert.ToInt64(dgvReciboPagoSalario.CurrentRow.Cells["Salario por Hora"].Value);

            Subtotal = ((HO * SXH) + ((SXH * 2) * HF));

            dgvReciboPagoSalario.CurrentRow.Cells["Subtotal Recibido"].Value = Subtotal;


            if (!string.IsNullOrEmpty(dgvReciboPagoSalario.CurrentRow.Cells["Deducciones Préstamo"].Value.ToString()))
            {
                DeduccionesPrestamo = Convert.ToInt64(dgvReciboPagoSalario.CurrentRow.Cells["Deducciones Préstamo"].Value);
            }

            DeduccionesCCSS = Convert.ToInt64(dgvReciboPagoSalario.CurrentRow.Cells["Deducciones CCSS"].Value);

            Total = (Subtotal - (DeduccionesCCSS + DeduccionesPrestamo));

            dgvReciboPagoSalario.CurrentRow.Cells["Total Recibido"].Value = Total;                               
        }

提前致谢!

【问题讨论】:

    标签: c# winforms datagridview


    【解决方案1】:

    从发布的代码看来,它似乎正在使用CurrentCellDirtyStateChanged 事件从其他列中的值设置Total Recibido 列。这将起作用,但是如果您要使用 DataTable 并将 Total Recibido 列设置为表中当前单元格的 Expression,则不需要 CurrentCellDirtyStateChanged 事件来处理此问题.

    例如,按照发布的代码并使用DataTable 一个可能的Expression 作为Total Recibido 列可能如下所示。添加的最后一列是Total 列的Expression

    private DataTable GetDT() {
      DataTable dt = new DataTable();
      dt.Columns.Add("Name", typeof(string));
      dt.Columns.Add("OrdinaryHours", typeof(double));
      dt.Columns.Add("HourlyWage", typeof(double));
      dt.Columns.Add("HolidayHours", typeof(double));
      dt.Columns.Add("CCSSDeductions", typeof(double));
      dt.Columns.Add("LoanDeductions", typeof(double));
      DataColumn dc = new DataColumn("Total", typeof(double));
      dc.Expression = "((OrdinaryHours * HourlyWage) + (HourlyWage * 2) * HolidayHours) - (CCSSDeductions + LoanDeductions)";
      dt.Columns.Add(dc);
      return dt;
    }
    

    将上述DataTableExpression 列一起用于Totals 将消除对CurrentCellDirtyStateChanged 事件的需要。 Totals 列单元格会在其他所有单元格都有数据后自动更新。

    此外,从帖子看来,您没有收到这个DataError,恕我直言,这是一个问题。由于所讨论的列是数字类型(int、double..等),因此当用户键入字符而不是数字并尝试离开单元格时,将抛出 DataError

    我猜如果你“捕捉”用户KeyPressed 事件并简单地忽略任何无效字符,它可能会更容易和更用户友好。示例:如果您捕获用户KeyPressed 输入,并且它位于应该是数字的列之一并且它不是数字或小数点,则忽略输入。使用此实现,用户将无法输入除数字和小数点以外的字符。这将防止DataError 被这些列抛出。

    为了实现这一点,您需要为目标列中的单元格实现“KeyPressed”事件。当此事件触发时,它可以检查并忽略任何无效字符。需要连接的事件是DataGridViewsEditingControlShowing 事件。当用户键入单元格时,将触发此事件。首先,检查用户输入的单元格是否在数字列之一中。如果是,那么您只需将KeyPressed 事件注册到该单元格。然后KeyPressed 事件将被触发,您可以检查正确的字符值。

    下面是KeyPressed 事件的示例。

    private void DoubleColumn_KeyPress(object sender, KeyPressEventArgs e) {
      // if the key pressed is not a control key or a digit or decimal - then ignore this character
      if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.') {
        e.Handled = true;
      }
      // check for multiple decimal points as only one is valid
      if (e.KeyChar == '.' && (sender as TextBox).Text.IndexOf('.') > -1) {
        e.Handled = true;
      }
    }
    

    然后要使用此事件,我们只需在用户键入数字列单元格时将事件注册到单元格中。此事件是EditingControlShowing 事件。在这种情况下,会检查它是否是一个数字列,然后注册 KeyPressed 事件以针对该单元格触发。

    private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
      e.Control.KeyPress -= new KeyPressEventHandler(DoubleColumn_KeyPress);
      if (dataGridView1.CurrentCell.ColumnIndex == 1 || dataGridView1.CurrentCell.ColumnIndex == 2 ||
          dataGridView1.CurrentCell.ColumnIndex == 3 || dataGridView1.CurrentCell.ColumnIndex == 4 ||
          dataGridView1.CurrentCell.ColumnIndex == 5) {
        e.Control.KeyPress += new KeyPressEventHandler(DoubleColumn_KeyPress);
      }
    }
    

    无论DataGridView 是否绑定数据,上述两种方法都应该有效。希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-09-21
      • 2011-05-16
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 2013-01-15
      相关资源
      最近更新 更多