如何检测 datagridview 行中的变化?

How to detect changes in a datagridview row?

我有一个包含 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 事件仅在单元格离开编辑模式或焦点更改时触发到另一个单元格。

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

为 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();
}

根据需要修改行为。

what I want is an event, function or method to detect the change in the rows

您是否希望在操作员完成编辑一行中的一个或多个单元格并且select要编辑另一行时立即收到通知?在那种情况下使用事件 DataGridView.RowValidatingDataGridView.RowValidated.

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

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

要能够看到所有更改:

使用 visual studio 设计器,您可能会添加列。您需要指定哪一列应显示哪个 属性:

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();
}

现在假设您决定操作员单击立即应用按钮以通知必须处理编辑的数据。

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 和 selected DisplayedPurchases 感兴趣(如果多select)

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);
}