Winformsアプリがあり、DataGridView
コントロールに埋め込まれたチェックボックスがオン/オフになったときにコードをトリガーしたい。私が試したすべてのイベント
CheckBox
がクリックされるとすぐに、チェックされた状態が変わる前にトリガーする、またはCheckBox
がフォーカスを失うとトリガーしますチェックされた状態が変更された直後にトリガーするイベントを見つけることができないようです。
編集:
私が達成しようとしているのは、1つのCheckBox
のDataGridView
のチェック状態が変化すると、他の2つのDataGridView
sのデータが変化することです。しかし、私が使用したすべてのイベント、他のグリッドのデータは、最初のCheckBox
のDataGridView
がフォーカスを失った後にのみ変化します。
DatGridView
s CheckedChanged
イベントを処理するには、最初にCellContentClick
を発生させて(CheckBox
es現在の状態がない!)、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();
}
これがお役に立てば幸いです。
追伸この記事を確認してください https://msdn.Microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v = vs.110).aspx
@Killercamのソリューションが機能することを発見しましたが、ユーザーがダブルクリックするのが速すぎると少し危険でした。他の人がそのケースを見つけたかどうかはわかりません。私は別の解決策を見つけました こちら 。
データグリッドのCellValueChanged
およびCellMouseUp
を使用します。チャンホンは説明します
「その理由は、OnCellvalueChangedイベントは、編集が完了したとDataGridViewが判断するまで発生しないためです。OnCellvalueChangedは、各キーストライクに対して[bother]発生しないため[TextBox Column]理にかなっています]。
ここに彼の例からの動作があります:
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();
}
}
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();
}
}
これはキーボードのアクティベーションも処理します。
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.....
}
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
}
}
}
コードは次のとおりです。
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);
}
}
この問題に対するより簡単な答えを見つけました。単純に逆論理を使用します。コードは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つは、複数のイベントが必要ないことです。
セルを編集すること、つまりセルが実際に編集されていないという問題なので、チェックボックスをクリックするとイベントを取得するためにセルまたは行の変更を保存する必要があります。
datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
これにより、別のイベントでも使用できます。
イベント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;
}
}
}
コードは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;
}
}
}
私のために働いたのは、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();
}
セル値の変更後にフォーカスを削除すると、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);
}
}
Devexpress xtragridを使用する際にこれを行うには、 here のように、対応するリポジトリアイテムの 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ループを使用して行を反復処理する必要があることに注意してください。
チェックボックスをクリックしてすぐにセルに値をコミットさせ、CellValueChangedイベントをキャッチできます。 CurrentCellDirtyStateChangedは、チェックボックスをクリックするとすぐに起動します。
次のコードは私のために機能します:
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
SendKeys.Send("{tab}");
}
その後、コードをCellValueChangedイベントに挿入できます。
この問題に対するより簡単な答えを見つけました。単純に逆論理を使用します。コードはVBにありますが、C#と大差ありません。
Private Sub DataGridView1_CellContentClick(sender As Object, e As
DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
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つは、複数のイベントが必要ないことです。
ここからいくつかの回答を試しましたが、常に何らかの問題(ダブルクリックやキーボードの使用など)がありました。そこで、それらのいくつかを組み合わせて、一貫した動作を得ました(完璧ではありませんが、適切に動作します)。
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.
}