DataGridView CheckBox ईवेंट परिवर्तन का पता कैसे लगाएं?


90

मेरे पास एक winforms ऐप है और कुछ कोड को ट्रिगर करना चाहते हैं जब एक चेकबॉक्स एक DataGridViewनियंत्रण में एम्बेडेड / अनचेक किया जाता है। हर घटना मैंने या तो कोशिश की है

  1. CheckBoxक्लिक होते ही ट्रिगर लेकिन इसकी जाँच की गई स्थिति से पहले, या
  2. ट्रिगर केवल एक बार CheckBoxअपना ध्यान केंद्रित करता है

मुझे लगता है कि जाँच की स्थिति में परिवर्तन के तुरंत बाद ट्रिगर होने वाली घटना नहीं मिल सकती है।


संपादित करें:

मैं जो हासिल करने की कोशिश कर रहा हूं, वह यह है कि जब किसी एक CheckBoxमें चेक की गई स्थिति DataGridViewबदल जाती है, तो दो अन्य DataGridViewएस में डेटा बदल जाता है। फिर भी मैंने सभी घटनाओं का उपयोग किया है, दूसरे ग्रिड में डेटा केवल CheckBoxपहले DataGridViewलूप फ़ोकस के बाद बदलता है ।


2
क्या आपने CurrentCellDirtyStateChangedईवेंट की जाँच की ?
योगराज गुप्ता

अभी भी केवल तभी निष्पादित होता है जब उपयोगकर्ता सेल छोड़ता है।
PJW

1
यहाँ इस पर MSDN लेख है: msdn.microsoft.com/en-us/library/… इसी तरह लेकिन किल्सरम के उत्तर से थोड़ा अलग
डेविड हॉल

जवाबों:


96

DatGridViewएस CheckedChangedईवेंट को संभालने के लिए आपको सबसे पहले CellContentClickआग लगानी चाहिए (जिसमें CheckBoxवर्तमान स्थिति नहीं है!) फिर कॉल करें 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 से लिंक ढूंढें और लेख लिंक पर क्लिक करें!
ल्यूक

1
मैंने इस समाधान पर लंबे समय तक खर्च नहीं किया और अगर @ 56ka का समाधान एक बेहतर, महान है। हालाँकि, मुझे यकीन नहीं है कि डबल क्लिक करने के बारे में सभी उपद्रव क्या DataGridViewCheckBoxहै। यह WPF नहीं है और नियंत्रण पर डबल क्लिक करने से कोई डेटा बाइंडिंग नहीं टूट रही है, यह WinForms है। डबल क्लिकिंग नियंत्रण को दृष्टिगत रूप से अपडेट नहीं कर सकता है लेकिन यह कुछ भी नहीं तोड़ता है और इस मामले में शायद नीचे का समाधान बेहतर है। धन्यवाद।
MoonKnight

अगर आप से एक ही कोड जोड़ने यह पूरी तरह से काम करता है CellContentClickमें CellContentDoubleClickके रूप में अच्छी तरह से। CellMouseUpसेल चयनित होने पर भी आग लग जाएगी लेकिन चेकबॉक्स पर क्लिक नहीं किया जाता है - जो वांछित व्यवहार नहीं है।
टारपीड शिकार

89

मुझे @ किलकारम का काम करने का समाधान मिला, लेकिन अगर उपयोगकर्ता ने बहुत तेजी से क्लिक किया तो वह थोड़ा चकमा दे गया। यकीन नहीं होता कि दूसरे ने पाया कि मामला या तो। मुझे यहां एक और समाधान मिला ।

यह डेटाग्रिड CellValueChangedऔर का उपयोग करता है CellMouseUp। चनघोंग बताते हैं कि

"इसका कारण यह है कि OnCellvalueChanged इवेंट तब तक फायर नहीं करेगा जब तक कि DataGridView आपके द्वारा संपादित पूरा कर लिया गया हो। यह टेक्स्टबॉक्स कॉलम के लिए इंद्रियाँ बनाता है, क्योंकि OnCellvalueChanged प्रत्येक कुंजी स्ट्राइक के लिए फायर करने के लिए [परेशान] नहीं करेगा, लेकिन यह [नहीं करता है] चेकबॉक्स के लिए समझदारी]।

यहाँ यह उनके उदाहरण से कार्यवाही में है:

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 घटना को माउसअप इवेंट से अलग माना जाता है। यदि DoubleClick ईवेंट का पता चला है, तो अनुप्रयोग पहले माउसअप इवेंट को पूरी तरह से अनदेखा कर देगा। इस तर्क को माउसअप इवेंट के अलावा सेलडबलक्लिक इवेंट में जोड़ना होगा:

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
मैं उत्तरदाता द्वारा बताई गई डबल-क्लिक समस्या में भाग गया, और इसने सही तरीके से निपटने में पहले समाधान की तुलना में बहुत बेहतर काम किया।
स्टीव फर्ग्यूसन

1
मैं भी डबल-क्लिक की समस्या में भाग गया और इस समाधान ने इसे ठीक कर दिया।
क्रिस सी

'यहां' बटन पर क्लिक करें और लेख देखें। मैं डबल क्लिक के साथ एक ही मुद्दा था।
ल्यूक

4
क्या होगा अगर आप स्पेस बार के साथ टॉगल टॉगल करें?
हाफगैर 11

1
स्पेसबार समस्या को 'ठीक' करने के लिए, मैं KeyPreviewफॉर्म पर सही और e.KeyCode == Keys.Spaceसेट पर सेट करता हूँ e.Handled = true। दूसरे शब्दों में, मैंने अभी-अभी कीबोर्ड संपादन को अक्षम किया है।
हाफगर्ल

9

jsturtevants के समाधान ने बहुत अच्छा काम किया। हालांकि, मैंने एंडडिट इवेंट में प्रोसेसिंग करने का विकल्प चुना। मैं इस दृष्टिकोण (मेरे आवेदन में) को पसंद करता हूं, क्योंकि सेलवैल्यूचेंज्ड घटना के विपरीत, एंडीडिट इवेंट में आग नहीं लगती है जब आप ग्रिड को आबाद कर रहे होते हैं।

यहाँ मेरा कोड है (जो का हिस्सा 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

यहाँ कुछ कोड है:

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पूरे समाधान है।
बेन वोयगेट

4

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

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 में लूप करेगा और चेकबॉक्स कॉलम की जांच होने पर चेक करेगा

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

घटना में CellContent आप इस रणनीति का उपयोग कर सकते हैं:

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 इवेंट को संभालना आवश्यक है । परिवर्तित मूल्य को पोस्ट करने के लिए ग्रिड व्यू 1.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 doesn't एक एन्यूमरेटर प्रदान करता है जो पंक्तियों पर पुनरावृति करने के लिए लूप के लिए उपयोग करना आवश्यक है।


0

सेल मान परिवर्तन के बाद फ़ोकस हटाने से मान DataGridView में अद्यतन करने की अनुमति देते हैं। CurrentCell को शून्य करने के लिए सेट करके फ़ोकस निकालें।

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

आप चेकबॉक्स पर क्लिक करते ही सेल को मान देने के लिए बाध्य कर सकते हैं और फिर सेलवैल्यूहैन्ड इवेंट को पकड़ सकते हैं । CurrentCellDirtyStateChanged के रूप में आप चेकबॉक्स पर क्लिक करें ही सक्रिय होता है।

निम्नलिखित कोड मेरे लिए काम करता है:

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

उसके बाद आप अपना कोड CellValueChanged इवेंट में सम्मिलित कर सकते हैं ।


0

बेन वायगट ने ऊपर टिप्पणी-उत्तर में सबसे अच्छा समाधान पाया:

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

गंभीरता से, बस इतना ही चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.