C# DataGridView在更改复选框值后直接更新数据源

C# DataGridView在更改复选框值后直接更新数据源,c#,.net,winforms,datagridview,datagridviewcheckboxcell,C#,.net,Winforms,Datagridview,Datagridviewcheckboxcell,我有一个System.Windows.Forms DataGridView,它绑定到一个列表 类MyObject包含绑定到DataGridView中DataGridViewCheckboxCell的布尔属性 public class MyObject { public decimal DefaultValue {get; set; } public bool HasCustomValue {get;set; } public decimal CustomValue {ge

我有一个System.Windows.Forms DataGridView,它绑定到一个
列表

类MyObject包含绑定到DataGridView中DataGridViewCheckboxCell的布尔属性

public class MyObject
{
    public decimal DefaultValue {get; set; }
    public bool HasCustomValue {get;set; }
    public decimal CustomValue {get;set; }
    public decimal CurrentValue
    {
        get
        {
            return HasCustomValue
                ? CustomValue
                : DefaultValue;
        }
}
如果我更改
HasCustomValue
的值,另一个(只读)属性
CurrentValue
也会更改它的值。 这是通过实现INotifyPropertyChanged事件来实现的(为了简单起见,我在源代码示例中保留了该部分)

如果我从DataGridView外部更改了
HasCustomValue
,绑定到
CurrentValue
的列将立即更新。 但是,如果用户启用/禁用复选框,
HasCustomValue
不会在基础数据源中更改,除非用户通过单击鼠标或按TAB键离开该列

有没有办法在更改复选框值后直接强制网格更新数据源


如果绑定控件属性,我可以将
DataSourceUpdateMode
设置为
Windows.Forms.DataSourceUpdateMode.OnPropertyChanged
,但我在DataGridView中没有找到类似的内容

我假设您使用的是bindingsource,然后在复选框中单击事件/编辑执行以下操作

    BindingSource.EndEdit()

我也有类似的问题。我使用的不是
BindingSource
,而是
bindingslist
。在经历了大量的挫折和试验后(以及遵循不同的解决方案,但效果并不理想)

我只是这样做:

  • 覆盖
    DataGridView
    CellMouseUp
    事件
  • 在这种情况下,调用
    DataGridView
    EndEdit()
    方法
    • 我做了这个把戏:

      • 将列的with CheckBox ReadOnly属性设置为true
      • 然后在CellContentClick中,以编程方式将该值更改为相反的值

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            int chkBoxColIdx = 0; //Index of the column with checkbox.
            if (e.ColumnIndex == chkBoxColIdx)
            {
                dataGridView1.Rows[e.RowIndex].Cells[chkBoxColIdx].Value = !(bool)dataGridView1.Rows[e.RowIndex].Cells[chkBoxColIdx].Value;
            }
        

      使用datagridview的处理程序。CurrentCellDirtyStateChanged

private void datagridview_CurrentCellDirtyStateChanged(Object sender, EventArgs e)
{
    //_checkboxColumnIndex - index of your checkboxcolumn
    DataGridView dgv = (DataGridView)sender;
    if (_checkboxColumnIndex == dgv.CurrentCell.ColumnIndex &&
        dgv.Columns[_checkboxColumnIndex].GetType() == typeof(DataGridViewCheckBoxColumn) &&
        dgv.IsCurrentCellDirty == true)
    {          
        //Remember that here dgv.CurrentCell.Value is previous/old value yet
        YourObject.HasCustomValue = !(bool)dgv.CurrentCell.Value
    }

    dgv.CommitEdit(DataGridViewDataErrorContexts.Commit) //this will fire .CellEndEdit event
}

我可以想象,您不想让bindingSource知道它绑定到什么。毕竟,这不是创建bindingSource的原因:能够让它绑定到几乎任何东西

因此,您自然不想知道当前项目的值是如何更改的;您只想知道它已被更改

为此,请使用event BindingSource.CurrentItemChanged:无论使用何种方法更改数据,都会收到通知

绑定到BindingSource的视图必须告诉BindingSource更改值已完成;编辑属性已结束

在您的例子中,视图是DataGridView。DataGridView告诉BindingSource当前单元格已使用DataGridView.EndEdit()完成更改

通常,在键入单元格时,当单元格失去焦点或按esc键时,编辑将结束。这使您有机会更正键入错误或取消编辑,以防不需要更改

但是,对于DataGridViewCheckBoxCell,大多数人希望在单击DataGridViewCheckBoxCell后立即完成编辑

因此,您需要处理事件DataGridView.CurrentCellDirtyStateChanged

// Whenever a DataGridViewCheckBoxCell becomes dirty editing is finished:
private void OnCurrentCellDirtyChanged(object sender, EventArgs e)
{
    if (this.dataGridView1.CurrentCell is DataGridViewCheckBoxCell;
    {
        this.dataGridView1.EndEdit();
    }
}

这将导致事件绑定源。CurrentItemChanged

能否显示DataGridView标记?它是WinForms,因此我没有标记代码;)我真的想不出C#中有任何元素既没有代码也没有标记。它可能是一个可视化设计器,但仍然有代码。你确定没有标记代码吗?反正我不会命名设计器代码标记代码,我没有设置任何特殊属性,只是在DataGridView中添加了一个复选框列和一些文本框列。我想我会按照alliswell的建议处理Click事件。虽然
EventArgs
对象没有
e.ColumnIndex
,但这对我来说是可行的。您可以使用
dgv.CurrentCell.ColumnIndex
而不是
e.ColumnIndex
。将column属性设置为只读对我也有效,代码放入OnClick事件中。在DataGridView上使用InvalidateCell方法,然后设置单元格值,