DataGridView CheckBox 이벤트 변경을 감지하는 방법은 무엇입니까?


92

winforms 앱이 있고 DataGridView컨트롤에 포함 된 확인란 이 선택 / 선택 취소 될 때 일부 코드를 트리거하고 싶습니다 . 내가 시도한 모든 이벤트

  1. CheckBox클릭 하자마자 선택된 상태가 변경되기 전에 트리거됩니다.
  2. CheckBox초점을 잃은 경우에만 트리거됩니다.

확인 된 상태가 변경된 직후에 트리거되는 이벤트를 찾을 수없는 것 같습니다.


편집하다:

내가 달성하려는 CheckBox것은 하나 의 체크 상태가 DataGridView변경되면 다른 두 개의 데이터가 변경 된다는 것 DataGridView입니다. 그러나 내가 사용한 모든 이벤트, 다른 그리드의 데이터 CheckBox는 첫 번째 DataGridView초점을 잃은 후에 만 변경 됩니다.


2
CurrentCellDirtyStateChanged이벤트 를 확인 하셨나요 ?
Yograj Gupta

사용자가 셀을 '떠나는'경우에만 여전히 실행됩니다.
PJW

1
여기에 대한 MSDN 기사가 있습니다. msdn.microsoft.com/en-us/library/… Killercam의 답변과 비슷하지만 약간 다릅니다
David Hall

답변:


98

DatGridViews CheckedChanged이벤트 를 처리하려면 먼저 CellContentClickto fire ( CheckBoxes 현재 상태 가 없습니다 !)를 가져온 다음을 호출해야 CommitEdit합니다. 그러면 CellValueChanged작업을 수행하는 데 사용할 수 있는 이벤트가 시작됩니다. 이것은 Microsoft의 감독 입니다. 다음과 같은 일을하십시오 ...

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

이게 도움이 되길 바란다.

PS이 기사 확인 https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx


5
이것은 좋은 해결책이지만 사용자가 여러 번 클릭하면 작동하지 않습니다. 대안이 아래에 게시되었습니다. stackoverflow.com/questions/11843488/…
56ka

1
또한 두 번 클릭 문제에이 솔루션을 사용하지 않는 것이 좋습니다. EndEdit () 함수를 호출해야합니다 ... @ 56ka에서 링크를 찾아서 기사 링크를 클릭하십시오!
Luke

1
나는이 솔루션에 오래 소비하지 않았으며 @ 56ka의 솔루션이 더 나은 솔루션이라면 훌륭합니다. 그러나 두 번 클릭하는 것에 대한 모든 소란이 무엇인지 잘 모르겠습니다 DataGridViewCheckBox. 이것은 WPF가 아니며 컨트롤을 두 번 클릭해도 데이터 바인딩이 중단되지 않으며 WinForms입니다. 두 번 클릭하면 컨트롤이 시각적으로 업데이트되지 않을 수 있지만 아무것도 손상 되지 않으며이 경우 아래 솔루션이 더 나은 솔루션 일 수 있습니다. 감사.
MoonKnight

당신이에서 동일한 코드를 추가 할 경우이 완벽하게 작동 CellContentClickCellContentDoubleClick뿐만 아니라. CellMouseUp셀이 선택되었지만 확인란을 클릭하지 않은 경우에도 실행됩니다. 이는 바람직한 동작이 아닙니다.
어리석은 먹이

89

@Killercam의 솔루션이 작동하는 것을 찾았지만 사용자가 너무 빨리 두 번 클릭하면 약간 이상했습니다. 다른 사람도 그 사건을 발견했는지 확실하지 않습니다. 여기서 다른 해결책을 찾았 습니다 .

그것은 데이터 그리드의 CellValueChangedCellMouseUp. Changhong은 다음과 같이 설명합니다.

"그 이유는 DataGridView에서 편집이 완료되었다고 생각할 때까지 OnCellvalueChanged 이벤트가 실행되지 않기 때문입니다. OnCellvalueChanged가 각 키 입력에 대해 실행되지는 않기 때문에 TextBox 열에 대해 의미가 있지만 [ 이해하기] CheckBox. "

다음은 그의 예에서 나온 것입니다.

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

그리고 체크 박스에 사용자가 필드를 떠날 때까지 기다리지 않고 클릭하면 편집이 완료되었음을 알리는 코드 :

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

편집 : DoubleClick 이벤트는 MouseUp 이벤트와 별도로 처리됩니다. DoubleClick 이벤트가 감지되면 애플리케이션은 첫 번째 MouseUp 이벤트를 완전히 무시합니다. 이 로직은 MouseUp 이벤트 외에도 CellDoubleClick 이벤트에 추가되어야합니다.

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
응답자가 지적한 두 번 클릭 문제가 발생했으며이 문제를 올바르게 처리하는 첫 번째 솔루션보다 훨씬 잘 작동했습니다.
Steve Ferguson

1
또한 두 번 클릭 문제가 발생하여이 솔루션이 해결되었습니다.
Chris C

'여기'버튼을 클릭하고 기사를 확인하십시오. 더블 클릭과 동일한 문제가 발생했습니다.
Luke

4
스페이스 바로 토글을 토글하면 어떨까요?
Halfgaar 2014.11.27

1
스페이스 바 문제를 '수정'하기 KeyPreview위해 양식에서 true로 설정 하고 e.KeyCode == Keys.Space, set e.Handled = true. 즉, 키보드 편집을 비활성화했습니다.
Halfgaar

9

jsturtevants의 솔루션은 훌륭하게 작동했습니다. 그러나 EndEdit 이벤트에서 처리를 선택했습니다. CellValueChanged 이벤트와 달리 그리드를 채우는 동안 EndEdit 이벤트가 발생하지 않기 때문에 내 응용 프로그램에서이 방법을 선호합니다.

내 코드는 다음과 같습니다. 일부는 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
좋은 대답이지만 사용자가 셀 내부를 클릭 할 때 후자가 호출되는 반면 체크 박스를 클릭 할 때만 전자가 호출되기 때문에 CellContentClick대신 사용 하는 것이 좋습니다 CellMouseUp.
제이미 킷슨

6

이것은 또한 키보드 활성화를 처리합니다.

    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

다음 Killercam'answer, 내 코드

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

및 :

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

5

다음은 몇 가지 코드입니다.

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
이 대답에는 마우스와 키보드 상호 작용을 모두 처리하는 정답이 포함되어 있으며 셀을 떠나지 않고 반복되는 상호 작용이 있습니다. 그러나 마지막 핸들러 만 필요 합니다. CommitEditfrom 호출 CurrentCellDirtyStateChanged이 전체 솔루션입니다.
Ben Voigt

2

셀 편집에 관한 것입니다. 실제로 셀이 편집되지 않은 문제이므로 확인란을 클릭 할 때 이벤트를 가져 오려면 셀 또는 행의 변경 사항을 저장해야이 기능을 사용할 수 있습니다.

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

이것으로 다른 이벤트에도 사용할 수 있습니다.


2

이 문제에 대한 더 간단한 답을 찾았습니다. 나는 단순히 역 논리를 사용합니다. 코드는 VB에 있지만 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

이것에 대한 가장 좋은 점 중 하나는 여러 이벤트가 필요 없다는 것입니다.


1

무엇 나를 위해 일한 것은이었다 CurrentCellDirtyStateChanged과 함께datagridView1.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

코드는 DataGridView에서 반복되며 CheckBox 열이 선택되었는지 확인합니다.

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

CellContentClick 이벤트에서 다음 전략을 사용할 수 있습니다.

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

여기에서 몇 가지 답변을 시도했지만 항상 두 번 클릭하거나 키보드를 사용하는 것과 같은 일종의 문제가있었습니다. 그래서 나는 그들 중 일부를 결합하여 일관된 행동을 얻었습니다 (완벽하지는 않지만 제대로 작동합니다).

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

devexpress xtragrid를 사용할 때이를 수행하려면 여기에 설명 된대로 해당 저장소 항목 의 EditValueChanged 이벤트 를 처리해야합니다 . 변경된 값이 게시되었는지 확인하기 위해 gridView1.PostEditor () 메서드를 호출하는 것도 중요합니다. 다음은 구현입니다.

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

xtragrid는 열거자를 제공하지 않기 때문에 for 루프를 사용하여 행을 반복해야합니다.


0

셀 값 변경 후 포커스를 제거하면 DataGridView에서 값을 업데이트 할 수 있습니다. CurrentCell을 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

확인란을 클릭 한 다음 CellValueChanged 이벤트 를 포착하자마자 셀이 값을 커밋하도록 강제 할 수 있습니다 . 는 CurrentCellDirtyStateChanged 당신이 확인란을 클릭 한 빨리 불을.

다음 코드가 저에게 효과적입니다.

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

그런 다음 CellValueChanged 이벤트에 코드를 삽입 할 수 있습니다 .


0

Ben Voigt는 위의 댓글 응답에서 최상의 솔루션을 찾았습니다.

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

진지하게, 그게 필요한 전부입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.