【问题标题】:How to detect changes in a datagridview row?如何检测 datagridview 行中的更改?
【发布时间】:2021-04-09 21:55:18
【问题描述】:

我有一个 15 列的数据网格视图。 行从中填充,我想要的是一个事件、函数或方法来检测行中的变化(不在单元格中)。

我试过了:

private void DGVPurchases_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    try
    {
        if (DGVPurchases.RowCount > 0)
        {
            switch (DGVPurchases.Columns[e.ColumnIndex].Name)
            {
                case "PurchaseEmisionDate":
                case "PurchaseVendorNumber":
                //others columns
                    if (!Convert.ToBoolean(DGVPurchases.Rows[e.RowIndex].Cells["PurchaseModified"].Value))
                            DGVPurchases.Rows[e.RowIndex].Cells["PurchaseModified"].Value = true;
                    break;
            }
        }
    }
    catch (Exception er)
    {
        PBLog.Save(this, er);
        Alert.Error(Error.Value, App.Purchase.Title);
    }
}

PurchaseModified 是一个复选框类型的列,当检测到单元格中的更改时设置为 true,但它不能很好地工作,因为 CellValueChanged 事件仅在单元格离开编辑模式或焦点更改到另一个单元格时触发。

【问题讨论】:

  • 你使用数据绑定吗?
  • 问题解决了吗?

标签: c# winforms datagridview


【解决方案1】:

我想要的是一个事件、函数或方法来检测行的变化

您是否希望在操作员完成对一行中的一个或多个单元格的编辑并选择另一行进行编辑时立即收到通知?在这种情况下使用事件DataGridView.RowValidating 和DataGridView.RowValidated。

不确定这是否是一个不错的界面。假设在输入客户地址的过程中,操作员决定从他屏幕上的文本编辑器中复制粘贴?

我认为一个好的人机界面是,你让操作员安心地完成他的任务,只有当操作员表示他完成了 DataGridView 的编辑时,你才应该开始处理编辑。

为了能够看到所有的变化:

使用 Visual Studio Designer,您可能会添加列。您需要指定哪个列应该显示哪个属性:

class DisplayedPurchase
{
    public int Id {set; set;}
    public DateTime EmisionDate {get; set;}
    public int VendorNumber {get; set;}
    ...
}

可能在你的构造函数中:

public MyForm() : base()
{
    InitializeComponents();

    this.columnId.DataPropertyName = nameof(DisplayedPurchase.Id);
    this.columnEmissionDate.DataPropertyName = nameof(DisplayedPurchase.EmissionDate);
    this.columnVendorNumber.DataPropertyName = nameof(DisplayedPurchase.VendorNumber);
    ...
}

您需要一个程序来获取必须显示的购买(超出此问题的范围)

public IEnumerable<DisplayedPurchase> FetchPurchases(...)
{
    ...
}

要显示购买并了解更改:使用 BindingList:

BindingList<DisplayedPurchase> DisplayedPurchases
{
    get => (BindingList<DisplayedPurchase>)this.dataGridView1.DataSource;
    set => this.dataGridView1.DataSource = value;
}

初始化数据网格视图:

private void InitDisplayedPurchases()
{
    this.DisplayedPurchases = new BindingList<DisplayedPurchase>(
        this.FetchPurchases(...).ToList());
}

private void OnFormLoading(object sender, ...)
{
    this.InitDisplayedPurchases();
}

现在假设您决定操作员单击 Apply-Now 按钮以通知必须处理已编辑的数据。

private void OnButtonApplyNow_Clicked(object sender, ...)
{
    ICollection<DisplayedPurchase> editedPurchases = this.DisplayedPurchases;
    // find out which data is changed and process them
    this.ProcessEditedPurchases(editedPurchases);
}

因为你把所有数据都放在了一个BindingList中,所以所有添加/删除/更改的行都自动在this.DisplayedPurchases中。

您可能还对当前的 DisplayedPurchase 和选定的 DisplayedPurchases(如果多选)感兴趣

DisplayedPurchase CurrentDisplayedPurchase => (DislayedPurchase)
    this.dataGridView1.CurrentRow?.DataBoundItem;

IEnumerable<DisplayedPurchase> SelectedPurchases => this.datGridView1.SelectedRows
    .Cast<DatGridViewRow>()
    .Select(row => row.DataBoundItem)
    .Cast<DisplayedPurchase>();

如果您真的想在行被编辑后立即处理,请考虑订阅事件 RowValidating 和 RowValidated:

public void OnRowValidated(object sender, DataGridViewCellEventArgs e)
{
    DataGridView dataGridView = (DataGridView)sender;
    DataGridViewRow row = dataGridView.Rows[e.RowIndex];
    DisplayedPurchase editedPurchase = (DisplayedPurchase)(row.DataBoundItem);
    this.ProcessEditedPurchase(editedPurchase);
}

【讨论】:

    【解决方案2】:

    我猜RowDirtyStateNeeded 就是你要找的。将 DataGridView 的 VirtualMode 属性设置为 true 并添加 RowDirtyStateNeeded 处理程序。触发事件时,检查QuestionEventArgs.Respose 是否为真。

    【讨论】:

      【解决方案3】:

      为 DataGridView 订阅事件:

      DGVPurchases.EditingControlShowing += DGVPurchases_EditingControlShowing;
      DGVPurchases.CellBeginEdit += DGVPurchases_CellBeginEdit;
      DGVPurchases.CellEndEdit += DGVPurchases_CellEndEdit;
      

      定义表单中的字段:

      private int rowIndex;
      private object originalValue;
      private TextBox cellTextBox;
      

      实现事件处理程序:

      private void DGVPurchases_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
      {
          cellTextBox = e.Control as TextBox;
          if (cellTextBox != null)
              cellTextBox.TextChanged += TextBox_TextChanged;
      }
      private void DGVPurchases_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
      {
          rowIndex = e.RowIndex;
          originalValue = DGVPurchases[e.ColumnIndex, e.RowIndex].Value;
      }
      private void DGVPurchases_CellEndEdit(object sender, DataGridViewCellEventArgs e)
      {
          if (cellTextBox != null)
              cellTextBox.TextChanged -= TextBox_TextChanged;
      }
      private void TextBox_TextChanged(object sender, EventArgs e)
      {
          DGVPurchases["PurchaseModified", rowIndex].Value =
              cellTextBox.Text != originalValue.ToString();
      }
      

      根据需要修改行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-12
        • 1970-01-01
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多