DataGridView CheckBox olay değişikliği nasıl tespit edilir?


92

Bir winforms uygulamam var ve bir DataGridViewkontrole gömülü bir onay kutusu işaretlendiğinde / işareti kaldırıldığında bazı kodları tetiklemek istiyorum . Denediğim her olay

  1. CheckBoxTıklandığında, ancak kontrol durumu değişmeden önce tetikler veya
  2. Yalnızca CheckBoxodak noktasını kaybettiğinde tetikler

Kontrol edilen durum değiştikten hemen sonra tetikleyen olay bulamıyorum.


Düzenle:

Başarmaya çalıştığım şey, CheckBoxbirindeki DataGridViewa'nın işaretli durumu değiştiğinde, diğer ikisindeki verilerin de DataGridViewdeğişmesidir. Yine de kullandığım tüm olaylar, diğer ızgaralardaki veriler ancak CheckBoxilk DataGridViewodadaki odak kaybından sonra değişiyor .


2
CurrentCellDirtyStateChangedEtkinliği kontrol ettiniz mi?
Yograj Gupta

Yine de yalnızca kullanıcı hücreden 'ayrıldığında' çalışır.
PJW

1
İşte bununla ilgili MSDN makalesi: msdn.microsoft.com/en-us/library/… benzer, ancak Killercam'ın cevabından biraz farklı
David Hall

Yanıtlar:


99

DatGridViewS CheckedChangedolayını işlemek için önce CellContentClickateş etmelisiniz ( CheckBoxmevcut durumu olmayan!), Sonra çağırmalısınız CommitEdit. Bu da CellValueChangedişinizi yapmak için kullanabileceğiniz olayı ateşleyecektir . Bu, Microsoft tarafından yapılan bir denetimdir . Aşağıdakine benzer bir şey yapın ...

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

Umarım bu yardımcı olur.

PS Bu makaleye bakın https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs.110).aspx


5
Bu iyi bir çözümdür ancak kullanıcı birkaç kez tıklarsa işe yaramaz, stackoverflow.com/questions/11843488/…
56ka

1
Ayrıca, çift tıklama sorunu için bu çözümü KULLANMAMAYI şiddetle tavsiye ederim. EndEdit () işlevinin çağrılması gerekiyor ... @ 56ka'daki bağlantıyı bulun ve makale bağlantısına tıklayın!
Luke

1
Bu çözüme fazla zaman harcamadım ve @ 56ka'nın çözümü daha iyiyse harika. Ancak, a'ya çift tıklamakla ilgili tüm telaşın ne olduğundan emin değilim DataGridViewCheckBox. Bu WPF değildir ve denetime çift tıklamak herhangi bir veri bağlamayı bozmuyor, WinForms. Çift tıklama görsel kontrolünü güncelleme olmayabilir ama değil kırmak şey ve bu durumda belki de aşağıda çözüm daha iyi biridir. Teşekkürler.
MoonKnight

Aynı kodu baştan CellContentClickiçine eklerseniz bu mükemmel çalışır CellContentDoubleClick. CellMouseUpHücre seçilse, ancak onay kutusu tıklanmasa bile, bu istenen bir davranış değildir.
torpid prey

89

@ Killercam'in çözümünün işe yaradığını buldum, ancak kullanıcı çok hızlı çift tıklarsa biraz tehlikeliydi. Başkalarının da davayı bulup bulmadığından emin değilim. Burada başka bir çözüm buldum .

Datagrid'in CellValueChangedve CellMouseUp. Changhong bunu açıklıyor

"Bunun nedeni, DataGridView düzenlemeyi tamamladığınızı düşünene kadar OnCellvalueChanged olayının tetiklenmemesidir. Bu, OnCellvalueChanged her tuş vuruşu için tetiklenmeyeceğinden, bir TextBox Sütunu için anlamlar yaratır, ancak [ bir CheckBox için mantıklı. "

İşte onun örneğinden hareket halinde:

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

Ve onay kutusuna, kullanıcının alandan çıkmasını beklemek yerine, tıklandığında düzenlemenin bittiğini söyleyen kod:

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

Düzenleme: Bir DoubleClick etkinliği, MouseUp etkinliğinden ayrı olarak ele alınır. Bir DoubleClick etkinliği tespit edilirse, uygulama ilk MouseUp olayını tamamen yok sayar. Bu mantığın, MouseUp olayına ek olarak CellDoubleClick olayına eklenmesi gerekir:

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
Yanıtlayanın belirttiği çift tıklama sorunuyla karşılaştım ve bu, doğru şekilde işlemede ilk çözümden çok daha iyi çalıştı.
Steve Ferguson

1
Ayrıca çift tıklama sorunuyla karşılaştım ve bu çözüm sorunu çözdü.
Chris C

'Burada' düğmesine tıklayın ve makaleye göz atın. Çift tıklama ile aynı sorunu yaşadım.
Luke

4
Boşluk çubuğuyla geçişi değiştirirseniz ne olur?
Halfgaar

1
Boşluk çubuğu sorununu 'düzeltmek' için KeyPreview, formda true olarak ve ne zaman e.KeyCode == Keys.Spaceayarladım e.Handled = true. Başka bir deyişle, klavye düzenlemeyi devre dışı bıraktım.
Halfgaar

9

jsturtevants'ın çözümü harika çalıştı. Ancak, işlemi EndEdit etkinliğinde yapmayı seçtim. Bu yaklaşımı tercih ediyorum (uygulamamda), çünkü CellValueChanged olayından farklı olarak, ızgarayı doldururken EndEdit olayı tetiklenmiyor.

İşte benim kodum (bir kısmı jsturtevant'tan çalındı:

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
İyi cevap, ancak bunun CellContentClickyerine kullanılması tercih edilir CellMouseUpçünkü ikincisi, kullanıcı hücrenin herhangi bir yerine tıkladığında çağrılırken, ilki yalnızca onay kutusu tıklandığında çağrılır.
Jamie Kitson

6

Bu aynı zamanda klavye aktivasyonunu da idare eder.

    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'ın yanıtını takiben, Benim kodum

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

ve :

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

İşte bazı kodlar:

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
Bu cevap, hem fare hem de klavye etkileşimlerini ve hücreyi terk etmeden tekrarlanan etkileşimleri yöneten doğru cevabı içerir. Ancak sadece son işleyiciye ihtiyaç vardır - CommitEditdan aramak CurrentCellDirtyStateChangedbütün çözümdür.
Ben Voigt

2

Her şey hücreyi düzenlemekle ilgili, sorun hücrenin fiilen düzenlenmemiş olması, bu yüzden bu işlevi kullanabilmek için onay kutusunu tıkladığınızda olayı almak için hücredeki veya satırdaki değişiklikleri kaydetmeniz gerekir:

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

bununla farklı bir etkinlikte bile kullanabilirsiniz.


2

Bu soruna daha basit bir cevap buldum. Ben sadece ters mantık kullanıyorum. Kod VB'dedir ancak C # 'dan çok farklı değildir.

 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

Bununla ilgili en iyi şeylerden biri, birden fazla etkinliğe gerek olmamasıdır.


1

Benim için işe yarayan şey CurrentCellDirtyStateChangedile kombinasyon halindeydidatagridView1.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

Kod DataGridView'da döngü oluşturacak ve CheckBox Sütununun Kontrol Edilip edilmediğini kontrol edecektir.

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 olayında bu stratejiyi kullanabilirsiniz:

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

Buradan bazı cevapları denedim, ancak her zaman bir tür problem yaşadım (çift tıklama veya klavyeyi kullanma gibi). Bu yüzden, bazılarını birleştirdim ve tutarlı bir davranışa sahip oldum (mükemmel değil ama düzgün çalışıyor).

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'i kullanırken bunu yapmak için, burada açıklandığı gibi karşılık gelen bir depo öğesinin EditValueChanged olayını işlemek gerekir . Değiştirilen değerin nakledildiğinden emin olmak için gridView1.PostEditor () yöntemini çağırmak da önemlidir. İşte bir uygulama:

        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 bir numaralandırıcı sağlamadığından, satırları yinelemek için bir for döngüsü kullanmak gerektiğini unutmayın.


0

Hücre değeri değişikliklerinden sonra odağın kaldırılması, değerlerin DataGridView'da güncellenmesine izin verir. CurrentCell'i null olarak ayarlayarak odağı kaldırın.

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

Hücreyi, onay kutusuna tıklar tıklamaz değeri teslim etmeye zorlayabilir ve ardından CellValueChanged olayını yakalayabilirsiniz . CurrentCellDirtyStateChanged Eğer onay kutusunu tıklayın kısa sürede yangını.

Aşağıdaki kod benim için çalışıyor:

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

Kodunuzu daha sonra CellValueChanged olayına ekleyebilirsiniz .


0

Ben Voigt en iyi çözümü yukarıdaki bir yorum-yanıtta buldu:

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

Cidden, tek ihtiyacınız olan bu.


0

VirtualMode = true ile DataGridView kullanıyorum ve yalnızca bu seçenek benim için çalıştı (hem fare hem de boşluk çubuğu çalışırken, tekrarlanan boşluk tıklamaları dahil):

private void doublesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
   var data_grid = (DataGridView)sender;
      
   if (data_grid.CurrentCell.IsInEditMode && data_grid.IsCurrentCellDirty) {
      data_grid.EndEdit();            
   }
}

private void doublesGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
   if (e.ColumnIndex == CHECKED_COLUMN_NUM && e.RowIndex >= 0 && e.RowIndex < view_objects.Count) { // view_objects - pseudocode   
     view_objects[e.RowIndex].marked = !view_objects[e.RowIndex].marked;        // Invert the state of the displayed object
   }
}  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.