Làm cách nào để phát hiện thay đổi sự kiện DataGridView CheckBox?


90

Tôi có một ứng dụng winforms và muốn kích hoạt một số mã khi hộp kiểm được nhúng trong một DataGridViewđiều khiển được chọn / bỏ chọn. Mọi sự kiện tôi đã thử

  1. Kích hoạt ngay sau khi CheckBoxđược nhấp nhưng trước khi trạng thái được kiểm tra của nó thay đổi, hoặc
  2. Chỉ kích hoạt một khi CheckBoxmất tiêu điểm

Tôi dường như không thể tìm thấy sự kiện kích hoạt ngay sau khi trạng thái đã chọn thay đổi.


Biên tập:

Những gì tôi đang cố gắng đạt được là khi trạng thái được kiểm tra của một CheckBoxtrong một DataGridViewthay đổi, dữ liệu trong hai DataGridViews khác sẽ thay đổi. Tuy nhiên, tất cả các sự kiện tôi đã sử dụng, dữ liệu trong các lưới khác chỉ thay đổi sau khi CheckBoxtrong lần đầu tiên DataGridViewmất tiêu điểm.


2
Bạn đã kiểm tra CurrentCellDirtyStateChangedSự kiện?
Yograj Gupta

Vẫn chỉ thực thi khi người dùng 'rời khỏi' ô.
PJW

1
Dưới đây là bài viết MSDN về điều này: msdn.microsoft.com/en-us/library/... tương tự nhưng hơi khác một chút để trả lời Killercam của
David Hall

Câu trả lời:


96

Để xử lý sự kiện DatGridViews, CheckedChangedtrước tiên bạn phải CellContentClickkích hoạt (không có CheckBoxtrạng thái hiện tại!) Sau đó gọi CommitEdit. Điều này lần lượt sẽ kích hoạt CellValueChangedsự kiện mà bạn có thể sử dụng để thực hiện công việc của mình. Đây là một sự giám sát của Microsoft . Làm một số điều như sau ...

private void dataGridViewSites_CellContentClick(object sender, 
    DataGridViewCellEventArgs e)
{
    dataGridViewSites.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

/// <summary>
/// Works with the above.
/// </summary>
private void dataGridViewSites_CellValueChanged(object sender, 
    DataGridViewCellEventArgs e)
{
    UpdateDataGridViewSite();
}

Tôi hi vọng cái này giúp được.

PS Kiểm tra bài viết này https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx


5
Đây là một giải pháp tốt nhưng không hoạt động nếu người dùng nhấp nhiều lần, một sự thay thế đã được đăng tải dưới đây stackoverflow.com/questions/11843488/...
56ka

1
Tôi cũng khuyên bạn KHÔNG nên sử dụng giải pháp này cho vấn đề nhấp đúp. Cần gọi hàm EndEdit () ... tìm link từ @ 56ka và click vào link bài viết!
Luke

1
Tôi đã không mất nhiều thời gian cho giải pháp này và nếu giải pháp của @ 56ka là giải pháp tốt hơn, thì thật tuyệt. Tuy nhiên, tôi không chắc tất cả những phiền phức về việc nhấp đúp vào a DataGridViewCheckBoxlà gì. Đây không phải là WPF và việc nhấp đúp vào điều khiển không phá vỡ bất kỳ ràng buộc dữ liệu nào, đó là WinForms. Nhấp đúp có thể không cập nhật điều khiển một cách trực quan nhưng nó không phá vỡ bất cứ điều gì và trong trường hợp này có lẽ giải pháp dưới đây là giải pháp tốt hơn. Cảm ơn.
MoonKnight

Điều này hoạt động hoàn hảo nếu bạn thêm cùng một mã từ CellContentClickvào CellContentDoubleClick. CellMouseUplà sẽ kích hoạt ngay cả khi ô được chọn nhưng hộp kiểm không được nhấp vào - đó không phải là hành vi mong muốn.
con mồi torpid vào

89

Tôi thấy giải pháp của @ Killercam hoạt động nhưng hơi khó xử nếu người dùng nhấp đúp quá nhanh. Không chắc liệu người khác có tìm thấy trường hợp đó không. Tôi đã tìm thấy một giải pháp khác ở đây .

Nó sử dụng datagrid's CellValueChangedCellMouseUp. Changhong giải thích rằng

"Lý do cho điều đó là sự kiện OnCellvalueChanged sẽ không kích hoạt cho đến khi DataGridView cho rằng bạn đã hoàn tất việc chỉnh sửa. Điều này có ý nghĩa đối với Cột TextBox, vì OnCellvalueChanged sẽ không [bận tâm] kích hoạt cho mỗi lần đánh phím, nhưng nó không [ có ý nghĩa] cho CheckBox. "

Đây là hành động từ ví dụ của anh ấy:

private void myDataGrid_OnCellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    {
        // Handle checkbox state change here
    }
}

Và mã để cho hộp kiểm biết rằng nó đã được chỉnh sửa xong khi được nhấp vào, thay vì đợi cho đến khi người dùng rời khỏi trường:

private void myDataGrid_OnCellMouseUp(object sender,DataGridViewCellMouseEventArgs e)
{
    // End of edition on each click on column of checkbox
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    {
        myDataGrid.EndEdit();
    }
}

Chỉnh sửa: Sự kiện DoubleClick được xử lý tách biệt với sự kiện MouseUp. Nếu sự kiện DoubleClick được phát hiện, ứng dụng sẽ hoàn toàn bỏ qua sự kiện MouseUp đầu tiên. Logic này cần được thêm vào sự kiện CellDoubleClick ngoài sự kiện MouseUp:

private void myDataGrid_OnCellDoubleClick(object sender,DataGridViewCellEventArgs e)
{
    // End of edition on each click on column of checkbox
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    {
        myDataGrid.EndEdit();
    }
}

3
Tôi đã gặp phải sự cố nhấp đúp được người phản hồi ghi nhận và giải pháp này hoạt động tốt hơn nhiều so với giải pháp đầu tiên trong việc xử lý chính xác.
Steve Ferguson

1
Tôi cũng gặp phải sự cố nhấp đúp và giải pháp này đã khắc phục nó.
Chris C,

Nhấp vào nút 'đây' và xem bài viết. Tôi đã gặp vấn đề tương tự với cú nhấp đúp.
Luke

4
Điều gì sẽ xảy ra nếu bạn chuyển đổi bằng phím cách?
Halfgaar

1
Để 'sửa chữa' vấn đề spacebar, tôi đặt KeyPreviewlà true về hình thức và khi e.KeyCode == Keys.Space, bộ e.Handled = true. Nói cách khác, tôi vừa tắt chỉnh sửa bàn phím.
Halfgaar

9

giải pháp của jsturtevants hoạt động tuyệt vời. Tuy nhiên, tôi đã chọn thực hiện xử lý trong sự kiện EndEdit. Tôi thích cách tiếp cận này hơn (trong ứng dụng của tôi) bởi vì, không giống như sự kiện CellValueChanged, sự kiện EndEdit không kích hoạt khi bạn đang điền vào lưới.

Đây là mã của tôi (một phần trong số đó bị đánh cắp từ jsturtevant:

private void gridCategories_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
    {
        //do some stuff
    }
}



private void gridCategories_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
    {
        gridCategories.EndEdit();
    }
}

3
Câu trả lời hay, nhưng nó được ưu tiên sử dụng CellContentClickthay CellMouseUpvì vì cái sau sẽ được gọi khi người dùng nhấp vào bất kỳ đâu bên trong ô trong khi cái trước chỉ được gọi khi hộp kiểm được nhấp.
Jamie Kitson

6

Điều này cũng xử lý việc kích hoạt bàn phím.

    private void dgvApps_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        if(dgvApps.CurrentCell.GetType() == typeof(DataGridViewCheckBoxCell))
        {
            if (dgvApps.CurrentCell.IsInEditMode)
            {
                if (dgvApps.IsCurrentCellDirty)
                {
                    dgvApps.EndEdit();
                }
            }
        }
    }


    private void dgvApps_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
          // handle value changed.....
    }

5

Đây là một số mã:

private void dgvStandingOrder_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (dgvStandingOrder.Columns[e.ColumnIndex].Name == "IsSelected" && dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
    {
        bool isChecked = (bool)dgvStandingOrder[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
        if (isChecked == false)
        {
            dgvStandingOrder.Rows[e.RowIndex].Cells["Status"].Value = "";
        }
        dgvStandingOrder.EndEdit();
    }
}

private void dgvStandingOrder_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{

    dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
    {
        dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }
}

2
Câu trả lời này chứa câu trả lời đúng, xử lý cả tương tác chuột và bàn phím và các tương tác lặp lại mà không cần rời khỏi ô. Nhưng chỉ cần trình xử lý cuối cùng - gọi CommitEdittừ CurrentCellDirtyStateChangedlà toàn bộ giải pháp.
Ben Voigt

4

đang theo dõi Killercam'answer, Mã của tôi

private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }

và:

private void dgvProducts_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if (dgvProducts.DataSource != null)
        {
            if (dgvProducts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "True")
            {
                //do something
            }
            else
            {
               //do something
            }
        }
    }

2

Tất cả chỉ là chỉnh sửa ô, vấn đề là ô không thực sự được chỉnh sửa, vì vậy bạn cần lưu Thay đổi của ô hoặc hàng để nhận sự kiện khi bạn nhấp vào hộp kiểm để bạn có thể sử dụng chức năng này:

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

với điều này, bạn có thể sử dụng nó ngay cả với một sự kiện khác.


2

Tôi đã tìm thấy một câu trả lời đơn giản hơn cho vấn đề này. Tôi chỉ đơn giản là sử dụng logic ngược lại. Mã bằng VB nhưng nó không khác nhiều so với C #.

 Private Sub DataGridView1_CellContentClick(sender As Object, e As 
 DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick

    Dim _ColumnIndex As Integer = e.ColumnIndex
    Dim _RowIndex As Integer = e.RowIndex

    'Uses reverse logic for current cell because checkbox checked occures 
     'after click
    'If you know current state is False then logic dictates that a click 
     'event will set it true
    'With these 2 check boxes only one can be true while both can be off

    If DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False And 
       DataGridView1.Rows(_RowIndex).Cells("Column3").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False
    End If

    If DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False And 
    DataGridView1.Rows(_RowIndex).Cells("Column2").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False
    End If


End Sub

Một trong những điều tốt nhất về điều này là không cần nhiều sự kiện.


1

Những gì làm việc cho tôi là CurrentCellDirtyStateChangedkết hợp vớidatagridView1.EndEdit()

private void dataGridView1_CurrentCellDirtyStateChanged( object sender, EventArgs e ) {
    if ( dataGridView1.CurrentCell is DataGridViewCheckBoxCell ) {
        DataGridViewCheckBoxCell cb = (DataGridViewCheckBoxCell)dataGridView1.CurrentCell;
        if ( (byte)cb.Value == 1 ) {
            dataGridView1.CurrentRow.Cells["time_loadedCol"].Value = DateTime.Now.ToString();
        }
    }
    dataGridView1.EndEdit();
}

1

Mã sẽ lặp lại trong DataGridView và Sẽ kiểm tra xem Cột CheckBox có được Kiểm tra hay không

private void dgv1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex == 0 && e.RowIndex > -1)
    {
        dgv1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        var i = 0;
        foreach (DataGridViewRow row in dgv1.Rows)
        {
            if (Convert.ToBoolean(row.Cells[0].Value))
            {
                i++;
            }
        }

        //Enable Button1 if Checkbox is Checked
        if (i > 0)
        {
            Button1.Enabled = true;
        }
        else
        {
            Button1.Enabled = false;
        }
    }
}

1

Trong trường hợp CellContentClick, bạn có thể sử dụng chiến lược này:

private void myDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{    
    if (e.ColumnIndex == 2)//set your checkbox column index instead of 2
    {   //When you check
        if (Convert.ToBoolean(myDataGrid.Rows[e.RowIndex].Cells[2].EditedFormattedValue) == true)
        {
            //EXAMPLE OF OTHER CODE
            myDataGrid.Rows[e.RowIndex].Cells[5].Value = DateTime.Now.ToShortDateString();

            //SET BY CODE THE CHECK BOX
            myDataGrid.Rows[e.RowIndex].Cells[2].Value = 1;
        }
        else //When you decheck
        {
            myDataGrid.Rows[e.RowIndex].Cells[5].Value = String.Empty;

            //SET BY CODE THE CHECK BOX
            myDataGrid.Rows[e.RowIndex].Cells[2].Value = 0;
        }
    }
}

1

Tôi đã thử một số câu trả lời từ đây, nhưng tôi luôn gặp một số vấn đề (như nhấp đúp hoặc sử dụng bàn phím). Vì vậy, tôi đã kết hợp một số trong số chúng và có được một hành vi nhất quán (nó không hoàn hảo, nhưng hoạt động đúng).

void gridView_CellContentClick(object sender, DataGridViewCellEventArgs e) {
  if(gridView.CurrentCell.GetType() != typeof(DataGridViewCheckBoxCell))
    return;
  if(!gridView.CurrentCell.IsInEditMode)
    return;
  if(!gridView.IsCurrentCellDirty)
    return;
  gridView.EndEdit();
}

void gridView_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e) {
  if(e.ColumnIndex == gridView.Columns["cFlag"].Index && e.RowIndex >= 0)
    gridView.EndEdit();
}

void gridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
  if(e.ColumnIndex != gridView.Columns["cFlag"].Index || e.RowIndex < 0)
    return;

  // Do your stuff here.

}

0

Để thực hiện việc này khi sử dụng devexpress xtragrid, cần phải xử lý sự kiện EditValueChanged của một mục kho lưu trữ tương ứng như được mô tả ở đây . Điều quan trọng nữa là gọi phương thức gridView1.PostEditor () để đảm bảo giá trị thay đổi đã được đăng. Đây là một triển khai:

        private void RepositoryItemCheckEdit1_EditValueChanged(object sender, System.EventArgs e)
        {
            gridView3.PostEditor();

            var isNoneOfTheAboveChecked = false;

            for (int i = 0; i < gridView3.DataRowCount; i++)
            {
                if ((bool) (gridView3.GetRowCellValue(i, "NoneOfTheAbove")) && (bool) (gridView3.GetRowCellValue(i, "Answer")))
                {
                    isNoneOfTheAboveChecked = true;
                    break;
                }
            }

            if (isNoneOfTheAboveChecked)
            {
                for (int i = 0; i < gridView3.DataRowCount; i++)
                {
                    if (!((bool)(gridView3.GetRowCellValue(i, "NoneOfTheAbove"))))
                    {
                        gridView3.SetRowCellValue(i, "Answer", false);
                    }
                }
            }
        }

Lưu ý rằng vì xtragrid không cung cấp kiểu liệt kê nên cần sử dụng vòng lặp for để lặp qua các hàng.


0

Loại bỏ tiêu điểm sau khi giá trị ô thay đổi cho phép các giá trị cập nhật trong DataGridView. Loại bỏ tiêu điểm bằng cách đặt CurrentCell thành null.

private void DataGridView1OnCellValueChanged(object sender, DataGridViewCellEventArgs dataGridViewCellEventArgs)
{
    // Remove focus
    dataGridView1.CurrentCell = null;
    // Put in updates
    Update();
}

private void DataGridView1OnCurrentCellDirtyStateChanged(object sender, EventArgs eventArgs)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }

}

0

Bạn có thể buộc ô cam kết giá trị ngay khi bạn nhấp vào hộp kiểm và sau đó bắt sự kiện CellValueChanged . Các CurrentCellDirtyStateChanged cháy ngay sau khi bạn nhấp vào hộp kiểm.

Đoạn mã sau phù hợp với tôi:

private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        SendKeys.Send("{tab}");
    }

Sau đó, bạn có thể chèn mã của mình vào sự kiện CellValueChanged .


0

Ben Voigt đã tìm ra giải pháp tốt nhất trong một bình luận-trả lời ở trên:

private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
        dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

Nghiêm túc mà nói, đó là TẤT CẢ bạn cần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.