DataGridView CheckBoxイベントの変更を検出する方法は?


90

WinFormsアプリがあり、コントロールに埋め込まれているチェックボックスDataGridViewがオン/オフになっているときにコードをトリガーしたいと思います。私が試したすべてのイベント

  1. CheckBoxクリックされるとすぐに、チェックされた状態が変わる前にトリガーされます。
  2. CheckBoxフォーカスを失ったときにのみトリガーされます

チェック状態が変化した直後にトリガーされるイベントが見つからないようです。


編集:

私が達成しようとしているのはCheckBox、1つのaのチェック状態がDataGridView変化すると、他DataGridViewの2つのsのデータも変化するということです。しかし、私が使用したすべてのイベントでは、他のグリッドのデータCheckBoxは、最初のグリッドがDataGridViewフォーカスを失った後にのみ変更されます。


2
CurrentCellDirtyStateChangedイベントをチェックしましたか?
Yograj Gupta 2012

それでも、ユーザーがセルを「離れる」ときにのみ実行されます。
PJW 2012

1
ここでは、この上のMSDNの記事は次のとおりです。msdn.microsoft.com/en-us/library/...似ていますが、Killercamの答えに少し異なる
デヴィッド・ホール

回答:


96

DatGridViewsCheckedChangedイベントを処理するには、最初にを起動する必要がありますCellContentClickCheckBoxesの現在の状態はありません!)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/…の

1
また、ダブルクリックの問題にはこのソリューションを使用しないことを強くお勧めします。EndEdit()関数を呼び出す必要があります... @ 56kaからリンクを見つけて、記事のリンクをクリックしてください。
ルーク

1
私はこのソリューションに長くは費やしませんでした。@ 56kaのソリューションがより優れているのであれば、すばらしいです。しかし、aをダブルクリックすることについてのすべての騒ぎが何であるかはわかりませんDataGridViewCheckBox。これはWPFではなく、コントロールをダブルクリックしてもデータバインディングが壊れることはなく、WinFormsです。ダブルクリックしてもコントロールが視覚的に更新されない場合がありますが、何も壊れません。この場合、おそらく以下の解決策の方が適しています。ありがとう。
MoonKnight 2014

あなたから同じコードを追加する場合、これは完璧に動作CellContentClickCellContentDoubleClickにも。CellMouseUpセルが選択されていてもチェックボックスがクリックされていなくても起動します。これは望ましくない動作です。
猛烈な獲物2018

89

@Killercamのソリューションは機能することがわかりましたが、ユーザーがダブルクリックするのが速すぎると少し危険でした。他の人がそのケースを見つけたかどうかはわかりません。私はここで別の解決策を見つけました。

これは、データグリッドのを使用CellValueChangedしてCellMouseUp。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
レスポンダーが指摘したダブルクリックの問題に遭遇しましたが、これは最初の解決策よりもはるかにうまく機能しました。
スティーブファーガソン2013年

1
また、ダブルクリックの問題が発生し、このソリューションで修正されました。
クリスC

「ここ」ボタンをクリックして、記事をチェックしてください。ダブルクリックでも同じ問題が発生しました。
ルーク

4
スペースバーでトグルを切り替えるとどうなりますか?
Halfgaar 2014年

1
スペースバーの問題を「修正」するためKeyPreviewに、フォームでtrueに設定し、の場合e.KeyCode == Keys.Spaceはに設定しe.Handled = trueます。つまり、キーボード編集を無効にしただけです。
Halfgaar 2014

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勧めします。
ジェイミーキットソン2017

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

ここにいくつかのコードがあります:

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
この回答には、マウスとキーボードの両方の操作、およびセルを離れることなく繰り返される操作を処理する正解が含まれています。呼び出し-しかし、唯一の最後のハンドラが必要とされているCommitEditからCurrentCellDirtyStateChanged、全体のソリューションです。
Ben Voigt 2018年

4

Killercamの答えに続いて、私のコード

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

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つは、複数のイベントの必要がないことです。


1

私のために働いたのはCurrentCellDirtyStateChangeddatagridView1.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.