Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# DataGridView复选框选择错误_C#_Winforms_Datagridview_Datagridviewcheckboxcell_.net Framework 4.8 - Fatal编程技术网

C# DataGridView复选框选择错误

C# DataGridView复选框选择错误,c#,winforms,datagridview,datagridviewcheckboxcell,.net-framework-4.8,C#,Winforms,Datagridview,Datagridviewcheckboxcell,.net Framework 4.8,我们的应用程序在DataGridView中显示了一个项目列表。第一列是DataGridViewCheckBoxColumn。我们希望我们的应用程序允许用户单击行上的任意位置,以选择第一列中的复选框 我们发现,如果用户直接点击复选框,选择/取消选择效果良好。如果用户单击其他列中的数据,情况也是如此 然而,如果用户只点击复选框的一侧,我们会得到奇怪的行为。未选中/取消选中该行中的复选框,但通常会选中另一行。为了更清楚地了解正在发生的事情,你可以查看我的网站 我尝试在代码中设置一些断点,例如,在Sel

我们的应用程序在DataGridView中显示了一个项目列表。第一列是DataGridViewCheckBoxColumn。我们希望我们的应用程序允许用户单击行上的任意位置,以选择第一列中的复选框

我们发现,如果用户直接点击复选框,选择/取消选择效果良好。如果用户单击其他列中的数据,情况也是如此

然而,如果用户只点击复选框的一侧,我们会得到奇怪的行为。未选中/取消选中该行中的复选框,但通常会选中另一行。为了更清楚地了解正在发生的事情,你可以查看我的网站

我尝试在代码中设置一些断点,例如,在SelectionChanged处理程序、CellClick处理程序和CellValueChanged处理程序上。我发现这些断点是以相同的模式命中的,无论我是单击复选框,还是单击复选框的一侧,还是单击其他列中的数据

有人见过这样的行为吗?你知道会发生什么吗?它是.NET DataGridView代码中的一个bug,还是我应该在代码中查找什么

这是相关的代码,请按要求(或者你可以下载一个)

从Form1.cs:

public Form1()
{
    InitializeComponent();
    dgsControl.SetUp();
}
从Form1.Designer.cs:

private void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    this.dgsControl = new DGSelection();
    this.Controls.Add(this.dgsControl);
    // 
    // dgsControl
    // 
    this.dgsControl.Dock = System.Windows.Forms.DockStyle.Fill;
    this.dgsControl.Location = new System.Drawing.Point(3, 3);
    this.dgsControl.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
    this.dgsControl.Name = "dgsControl";
    this.dgsControl.Size = new System.Drawing.Size(689, 325);
    this.dgsControl.TabIndex = 0;

    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(800, 450);
    this.Text = "DataGridView Demo";
}
private void InitializeComponent()
{
    components = new System.ComponentModel.Container();
    System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
    System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
    System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
    this.dgvTable = new System.Windows.Forms.DataGridView();
    this.colCheckboxes = new System.Windows.Forms.DataGridViewCheckBoxColumn();
    this.colText1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
    this.colText2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
    this.cbxCheckAll = new System.Windows.Forms.CheckBox();
    this.lbl_empty = new System.Windows.Forms.Label();
    ((System.ComponentModel.ISupportInitialize)(this.dgvTable)).BeginInit();
    this.SuspendLayout();
    // 
    // dgvTable
    // 
    this.dgvTable.AllowUserToAddRows = false;
    this.dgvTable.AllowUserToDeleteRows = false;
    this.dgvTable.AllowUserToResizeColumns = false;
    this.dgvTable.AllowUserToResizeRows = false;
    this.dgvTable.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
    this.dgvTable.BackgroundColor = System.Drawing.SystemColors.Window;
    this.dgvTable.BorderStyle = System.Windows.Forms.BorderStyle.None;
    this.dgvTable.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
    this.dgvTable.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
    dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
    dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.ControlDark;
    dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
    dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
    dataGridViewCellStyle1.Padding = new System.Windows.Forms.Padding(3);
    dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
    dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
    dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
    this.dgvTable.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
    this.dgvTable.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
    this.dgvTable.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
        this.colCheckboxes,
        this.colText1,
        this.colText2 });
    this.dgvTable.Dock = System.Windows.Forms.DockStyle.Fill;
    this.dgvTable.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
    this.dgvTable.EnableHeadersVisualStyles = false;
    this.dgvTable.Location = new System.Drawing.Point(0, 0);
    this.dgvTable.Margin = new System.Windows.Forms.Padding(2);
    this.dgvTable.MultiSelect = false;
    this.dgvTable.Name = "dgvTable";
    this.dgvTable.RowHeadersVisible = false;
    this.dgvTable.RowTemplate.Height = 24;
    this.dgvTable.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
    this.dgvTable.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect;
    this.dgvTable.Size = new System.Drawing.Size(484, 318);
    this.dgvTable.TabIndex = 0;
    this.dgvTable.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DGSelection_CellClick);
    this.dgvTable.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.DgvTableCellValueChanged);
    this.dgvTable.CurrentCellDirtyStateChanged += new System.EventHandler(this.DGSelection_CurrentCellDirtyStateChanged);
    this.dgvTable.SelectionChanged += new System.EventHandler(this.DGSelection_SelectionChanged);
    // 
    // colCheckboxes
    // 
    this.colCheckboxes.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None;
    this.colCheckboxes.Frozen = true;
    this.colCheckboxes.HeaderText = "";
    this.colCheckboxes.Name = "colCheckboxes";
    this.colCheckboxes.Resizable = System.Windows.Forms.DataGridViewTriState.False;
    this.colCheckboxes.Width = 30;
    // 
    // colText1
    // 
    this.colText1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
    dataGridViewCellStyle2.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0);
    this.colText1.DefaultCellStyle = dataGridViewCellStyle2;
    this.colText1.HeaderText = "Option";
    this.colText1.Name = "colText1";
    this.colText1.ReadOnly = true;
    this.colText1.Resizable = System.Windows.Forms.DataGridViewTriState.False;
    this.colText1.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
    this.colText1.Width = 57;
    // 
    // colText2
    // 
    this.colText2.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
    dataGridViewCellStyle3.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0);
    this.colText2.DefaultCellStyle = dataGridViewCellStyle3;
    this.colText2.HeaderText = "Description";
    this.colText2.Name = "colText2";
    this.colText2.ReadOnly = true;
    this.colText2.Resizable = System.Windows.Forms.DataGridViewTriState.False;
    this.colText2.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
    // 
    // cbxCheckAll
    // 
    this.cbxCheckAll.AutoSize = true;
    this.cbxCheckAll.BackColor = System.Drawing.SystemColors.ControlDark;
    this.cbxCheckAll.Location = new System.Drawing.Point(8, 5);
    this.cbxCheckAll.Margin = new System.Windows.Forms.Padding(2);
    this.cbxCheckAll.Name = "cbxCheckAll";
    this.cbxCheckAll.Size = new System.Drawing.Size(15, 14);
    this.cbxCheckAll.TabIndex = 1;
    this.cbxCheckAll.UseVisualStyleBackColor = false;
    this.cbxCheckAll.CheckedChanged += new System.EventHandler(this.cbxCheckAll_CheckedChanged);
    // 
    // lbl_empty
    // 
    this.lbl_empty.Anchor = ((System.Windows.Forms.AnchorStyles)
        (((System.Windows.Forms.AnchorStyles.Top |
           System.Windows.Forms.AnchorStyles.Left) |
           System.Windows.Forms.AnchorStyles.Right)));
    this.lbl_empty.BackColor = System.Drawing.Color.Transparent;
    this.lbl_empty.Location = new System.Drawing.Point(3, 25);
    this.lbl_empty.Name = "lbl_empty";
    this.lbl_empty.Size = new System.Drawing.Size(478, 44);
    this.lbl_empty.TabIndex = 2;
    this.lbl_empty.Text = "No data defined for the list";
    this.lbl_empty.Visible = false;
    // 
    // DGSelection
    // 
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.Controls.Add(this.lbl_empty);
    this.Controls.Add(this.cbxCheckAll);
    this.Controls.Add(this.dgvTable);
    this.Margin = new System.Windows.Forms.Padding(2);
    this.Name = "DGSelectionControl";
    this.Size = new System.Drawing.Size(484, 318);
    ((System.ComponentModel.ISupportInitialize)(this.dgvTable)).EndInit();
    this.ResumeLayout(false);
    this.PerformLayout();
}
从DGSelection.cs:

public partial class DGSelection : UserControl
{
    #region Member variables

    private class ListData
    {
        public string Option;
        public string Description;
    }
    private static readonly List<ListData> TestData = new List<ListData>
    {
        new ListData { Option = "Option1", Description = "Description1" },
        new ListData { Option = "Option2", Description = "Description2" },
        new ListData { Option = "Option3", Description = "Description3" },
        new ListData { Option = "Option4", Description = "Description4" }
    };

    public event EventHandler OptionsChanged;
    #endregion

    #region Constructor
    public DGSelection()
    {
        InitializeComponent();
        dgvTable.BackgroundColor = Color.DarkGray;
        dgvTable.DefaultCellStyle.BackColor = Color.DarkGray;
        dgvTable.DefaultCellStyle.ForeColor = Color.Black;
        dgvTable.ColumnHeadersDefaultCellStyle.BackColor = Color.DarkGray;
        dgvTable.ColumnHeadersDefaultCellStyle.ForeColor = Color.Black;
        dgvTable.GridColor = Color.DarkGray;
        cbxCheckAll.BackColor = Color.DarkGray;

        // Move label where it belongs (moved elsewhere in Designer for ease of editing).
        lbl_empty.Top = Top + 5;
    }
    #endregion

    #region Public Methods
    public void SetUp()
    {
        dgvTable.Rows.Clear();
        cbxCheckAll.Checked = false;
        bool anyRows = TestData.Any();
        lbl_empty.Visible = !anyRows;
        cbxCheckAll.Visible = anyRows;
        dgvTable.ColumnHeadersVisible = anyRows;

        foreach (ListData ld in TestData)
        {
            dgvTable.Rows.Add(false, ld.Option, ld.Description);
        }
    }
    #endregion

    #region Event Handlers
    private void DGSelection_SelectionChanged(object sender, EventArgs e)
    {
        dgvTable.ClearSelection();
    }

    private void cbxCheckAll_CheckedChanged(object sender, EventArgs e)
    {
        try
        {
            dgvTable.CellValueChanged -= DgvTableCellValueChanged;
            bool checkAll = cbxCheckAll.Checked;
            foreach (DataGridViewRow row in dgvTable.Rows)
                row.Cells[0].Value = checkAll;
        }
        finally
        {
            dgvTable.CellValueChanged += DgvTableCellValueChanged;
        }
        OptionsChanged?.Invoke(this, EventArgs.Empty);
    }

    private void DGSelection_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        if (e.RowIndex < 0)
            return; // Ignore clicks in the header row

        DataGridViewCell checkBoxCell = dgvTable.Rows[e.RowIndex].Cells[0];
        checkBoxCell.Value = !(bool)checkBoxCell.Value;
    }

    private void DgvTableCellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        try
        {
            cbxCheckAll.CheckedChanged -= cbxCheckAll_CheckedChanged;
            cbxCheckAll.CheckedChanged -= cbxCheckAll_CheckedChanged;
            // Not sure why, but sometimes subscribed twice

            bool checkAll = dgvTable.Rows.Count > 0;
            foreach (DataGridViewRow row in dgvTable.Rows)
                checkAll &= row.Cells[0].Value.Equals(true);
            cbxCheckAll.Checked = checkAll;
        }
        finally
        {
            cbxCheckAll.CheckedChanged += cbxCheckAll_CheckedChanged;
        }
        OptionsChanged?.Invoke(this, EventArgs.Empty);
    }

    private void DGSelection_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        dgvTable.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }
    #endregion
}
我们的代码中是否有导致这种行为的原因?或者它是DataGridView实现中的一个bug?我已经用.NET Framework v.4.6和v.4.8复制了这一点

(注意:从Microsoft Q&A论坛转载,因为我在那里没有收到任何回复。)

我建议进行以下更改(使用.Net Framework 4.8测试):

  • 不要使用复选框
    CheckedChanged
    事件:当它试图更改“全选”复选框状态时,它将干扰
    CellValueChanged
    事件。改为使用
    单击
    事件。
    这也将允许去掉所有那些添加处理程序/删除处理程序的东西

  • 单击单元格后立即调用以更新复选框单元格的状态:这将立即更新复选框值(这是您在单元格区域内而不是在复选框内容内单击时看到的问题:控件未立即更新)。
    有关更多详细信息,请参见此处的注释:

  • 删除
    committedit(DataGridViewDataErrorContexts.Commit):如果您需要立即更新一个值,请改为调用该方法(也请参阅有关该方法的说明)

  • 这就是它现在的工作原理:

    private void cbxCheckAll_单击(对象发送方,事件参数e)
    {
    if(dgvTable.Rows.Count==0)返回;
    试一试{
    bool checkAll=cbxCheckAll.Checked;
    foreach(dgvTable.Rows中的DataGridViewRow行){
    行。单元格[0]。值=checkAll;
    }
    }
    最后{
    optionChanged?.Invoke(此为EventArgs.Empty);
    }
    }
    私有void DGSelection_CellClick(对象发送方,DataGridViewCellEventArgs e)
    {
    如果(e.RowIndex<0)返回;
    bool currentValue=(bool)dgvTable[0,e.RowIndex].Value;
    dgvTable[0,e.RowIndex]。值=!currentValue;
    }
    私有void DgvTableCellValueChanged(对象发送方,DataGridViewCellEventArgs e)
    {
    如果(!dgvTable.IsHandleCreated)返回;
    cbxCheckAll.Checked=dgvTable.Rows.OfType().All(r=>(bool)r.Cells[0]。Value==true);
    dgvTable.BeginInvoke(新操作(()=>dgvTable.RefreshEdit());
    optionChanged?.Invoke(此为EventArgs.Empty);
    }
    
    谢谢@Jimi,继续关注。。。1.我想这是你从经验中学到的东西,而不是从文档中。。。2.明白了。CurrentCellDirtyStateChanged()中对CommitteIt()的调用是我在为Your's welcome()提供的示例代码中看到的:)--3<可以使用code>EndEdit()
    ,如我链接的代码所示,当没有要保留的编辑模式时,相反,我们希望立即提交,无需进一步ado。-如果您对这里的
    BeginInvoke()
    的使用有任何疑问,我可以写一个说明。
    private void cbxCheckAll_Click(object sender, EventArgs e)
    {
        if (dgvTable.Rows.Count == 0) return;
        try {
            bool checkAll = cbxCheckAll.Checked;
            foreach (DataGridViewRow row in dgvTable.Rows) {
                row.Cells[0].Value = checkAll;
            }
        }
        finally {
            OptionsChanged?.Invoke(this, EventArgs.Empty);
        }
    }
    
    private void DGSelection_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        if (e.RowIndex < 0) return;
    
        bool currentValue = (bool)dgvTable[0, e.RowIndex].Value;
        dgvTable[0, e.RowIndex].Value = !currentValue;
    }
    
    private void DgvTableCellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if (!dgvTable.IsHandleCreated) return;
        cbxCheckAll.Checked = dgvTable.Rows.OfType<DataGridViewRow>().All(r => (bool)r.Cells[0].Value == true);
        dgvTable.BeginInvoke(new Action(() => dgvTable.RefreshEdit()));
        OptionsChanged?.Invoke(this, EventArgs.Empty);
    }