Datagridview में Button Column में क्लिक इवेंट को कैसे हैंडल करें?


136

मैं C # का उपयोग करके एक विंडोज़ एप्लिकेशन विकसित कर रहा हूं। मैं DataGridViewडेटा प्रदर्शित करने के लिए उपयोग कर रहा हूं । मैंने उसमें एक बटन कॉलम जोड़ा है। मैं जानना चाहता हूं कि मैं DataGridView में उस बटन पर क्लिक घटना को कैसे संभाल सकता हूं।


1
क्या आप प्रोग्राम को बटन जोड़ रहे हैं (जैसा कि मुझे संदेह है कि एकमात्र तरीका है)?
XstreamINsanity

इसके लिए ऑनलाइन बहुत सारे उत्तर उपलब्ध हैं। क्या आपको विशेष रूप से परेशानी दे रहा है?
जोशुआ एवेन्सन

1
@ जोशुआ मुझे नेट पर कई जवाब मिले लेकिन वास्तव में यह अंदाजा नहीं था कि क्या करना है और कब शुरू करना है। मैंने अपने डाटाग्रिडव्यू में एक बटन जोड़ा था, बस इसके क्लिक इवेंट को संभालना नहीं जानता।
हिमाद्री

जवाबों:


263

आपने अपने लिए एक बटन जोड़ा है DataGridViewऔर जब वह क्लिक किया जाता है तो आप कुछ कोड चलाना चाहते हैं।
आसान मटर - बस इन चरणों का पालन करें:

क्या न करें:

सबसे पहले, यहाँ क्या नहीं करना है:

मैं यहाँ कुछ अन्य उत्तरों में सुझावों से बचूँगा और यहाँ तक कि MSDN पर प्रलेखन द्वारा प्रदान किया जाएगा ताकि यह निर्धारित किया जा सके कि कोई बटन क्लिक किया गया था या नहीं। क्लिक इवेंट पूरे ग्रिड के लिए रजिस्टर करता है, इसलिए किसी तरह आपको यह निर्धारित करने की आवश्यकता है कि एक बटन क्लिक किया गया था, लेकिन आपको यह मानकर ऐसा नहीं करना चाहिए कि आपका बटन एक विशेष कॉलम नाम या इंडेक्स में रहता है ... एक आसान तरीका है ...

इसके अलावा, सावधान रहें कि आप किस घटना को संभालना चाहते हैं। फिर, प्रलेखन और कई उदाहरणों से यह गलत हो जाता है। अधिकांश उदाहरण उस CellClickघटना को संभालते हैं जो आग लग जाएगी:

जब किसी सेल के किसी हिस्से पर क्लिक किया जाता है।

... लेकिन जब भी पंक्ति हैडर पर क्लिक किया जाएगा, तब भी आग लग जाएगी । यह निर्धारित करने के लिए अतिरिक्त कोड जोड़ने की आवश्यकता है कि क्या e.RowIndexमान 0 से कम है

इसके बजाय संभाल CellContentClickजो केवल होता है:

जब किसी कक्ष के भीतर की सामग्री को क्लिक किया जाता है

जो भी कारण के लिए, कॉलम हेडर को एक सेल के भीतर 'सामग्री' माना जाता है, इसलिए हमें अभी भी उसके लिए नीचे की जांच करनी होगी।

करने योग्य:

तो यहां आपको क्या करना चाहिए:

सबसे पहले, डाली टाइप करने के लिए इस DataGridViewयह डिजाइन समय में आंतरिक गुण है बेनकाब करने के लिए। आप पैरामीटर पर प्रकार को संशोधित कर सकते हैं, लेकिन यह कभी-कभी संचालकों को जोड़ने या हटाने को मुश्किल बना सकता है।

अगला, यह देखने के लिए कि क्या कोई बटन क्लिक किया गया है, बस यह सुनिश्चित करने के लिए जांचें कि घटना उठाने वाला स्तंभ प्रकार का है DataGridViewButtonColumn। क्योंकि हम भेजने वाले को पहले ही टाइप DataGridViewकर देते हैं, हम Columnsसंग्रह प्राप्त कर सकते हैं और वर्तमान कॉलम का उपयोग कर चयन कर सकते हैं e.ColumnIndex। फिर जांचें कि क्या वह वस्तु प्रकार की है DataGridViewButtonColumn

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

यह सब एक साथ डालें:

C # :

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    var senderGrid = (DataGridView)sender;

    if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
        e.RowIndex >= 0)
    {
        //TODO - Button Clicked - Execute Code Here
    }
}

VB :

Private Sub DataGridView1_CellContentClick(sender As System.Object, e As DataGridViewCellEventArgs) _
                                           Handles DataGridView1.CellContentClick
    Dim senderGrid = DirectCast(sender, DataGridView)

    If TypeOf senderGrid.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso
       e.RowIndex >= 0 Then
        'TODO - Button Clicked - Execute Code Here
    End If

End Sub

अपडेट 1 - कस्टम इवेंट

यदि आप थोड़ी सी मस्ती करना चाहते थे, तो जब भी डेटाग्रेड पर एक बटन क्लिक किया जाता है, आप अपनी खुद की घटना को बढ़ा सकते हैं। आप इसे स्वयं ही DataGrid में नहीं जोड़ सकते, बिना इनहेरिटेंस आदि के साथ गड़बड़ किए हुए, लेकिन आप अपने प्रपत्र में एक कस्टम ईवेंट जोड़ सकते हैं और उपयुक्त होने पर आग लगा सकते हैं। यह थोड़ा अधिक कोड है, लेकिन उल्टा यह है कि जब आप एक बटन क्लिक किया जाता है, तो यह निर्धारित करने के लिए कि आप क्या करना चाहते हैं, आपको अलग कर दिया गया है।

बस एक घटना घोषित करें, जब उचित हो, बढ़ाएं और इसे संभालें। यह इस तरह दिखेगा:

Event DataGridView1ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs)

Private Sub DataGridView1_CellContentClick(sender As System.Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
    Dim senderGrid = DirectCast(sender, DataGridView)
    If TypeOf senderGrid.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso e.RowIndex >= 0 Then
        RaiseEvent DataGridView1ButtonClick(senderGrid, e)
    End If
End Sub

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) Handles Me.DataGridView1ButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub

अपडेट 2 - विस्तारित ग्रिड

यदि हम एक ग्रिड के साथ काम कर रहे हैं तो यह बहुत अच्छा होगा। हम प्रारंभिक प्रश्न का उत्तर आसानी से दे सकते हैं you've added a button to your DataGridView and you want to run some code when it's clicked:। यहाँ एक दृष्टिकोण है जो विस्तार करता है DataGridView। यह प्रत्येक लाइब्रेरी के साथ एक कस्टम नियंत्रण देने के लिए परेशानी का कारण नहीं हो सकता है, लेकिन कम से कम यह अधिकतम एक बटन क्लिक किया गया था, यह निर्धारित करने के लिए इस्तेमाल कोड का पुन: उपयोग करता है।

बस इसे अपनी विधानसभा में जोड़ें:

Public Class DataGridViewExt : Inherits DataGridView

    Event CellButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs)

    Private Sub CellContentClicked(sender As System.Object, e As DataGridViewCellEventArgs) Handles Me.CellContentClick
        If TypeOf Me.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso e.RowIndex >= 0 Then
            RaiseEvent CellButtonClick(Me, e)
        End If
    End Sub

End Class

बस। इसे फिर कभी मत छुओ। सुनिश्चित करें कि आपका DataGrid एक प्रकार का है, DataGridViewExtजो DataGridView के समान ही कार्य करना चाहिए। सिवाय यह भी एक अतिरिक्त घटना है कि आप इस तरह से संभाल कर सकते हैं:

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) _
                                      Handles DataGridView1.CellButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub

1
VB.net में आपको कॉलम इंडेक्स की जाँच करने की आवश्यकता नहीं है। मैं dgv के लिए दो कॉलम के साथ इस सटीक उदाहरण का उपयोग कर रहा हूं। एक स्तंभ जो संपादन योग्य है और दूसरा एक हटाए गए बटटन के साथ। मैं सभी dgv पर क्लिक करता हूं और जब मैं बटन पर क्लिक करता हूं तो ईवेंट केवल बंद हो जाता है।
चमकदार

3
+1। हालाँकि, हमारे मामले में कॉलम एक सामान्य डेटाग्रिड व्यू कॉलेयम है, और मुझे सेल प्रकार की जाँच करनी थी:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
डेव जॉनसन

अपवोट्स और टिप्पणियों को देखते हुए मैं समझता हूं कि यह एक सही उत्तर है, लेकिन ... सब कुछ हमेशा इतना जटिल क्यों होना चाहिए! मैंने अभी तक WPF से संपर्क नहीं किया है, लेकिन, क्या यह वहीं होगा?
jj_

1
अद्यतन 2 के लिए सी # कोडpublic class DataGridViewExt : DataGridView { public event DataGridViewCellEventHandler CellButtonClick; public DataGridViewExt() { this.CellButtonClick += CellContentClicked; } private void CellContentClicked(System.Object sender, DataGridViewCellEventArgs e) { if (this.Columns[e.ColumnIndex].GetType() == typeof(DataGridViewButtonColumn) && e.RowIndex >= 0 ) { CellButtonClick.Invoke(this, e); } } }
टोनी चीथम

@tonyenkiducx, की सराहना की, लेकिन टिप्पणियाँ वास्तव में एक पूरी कक्षा के लिए वैकल्पिक वाक्यविन्यास दिखाने के लिए एक अच्छी जगह नहीं हैं, खासकर एक कोड कनवर्टर के माध्यम से आसानी से प्राप्त किया जा सकता है । निश्चित रूप से, लोग यहाँ c # की तलाश में आएंगे, लेकिन वे स्वयं वहाँ crosswalk कर सकते हैं और वैसे भी कार्यान्वयन की तलाश में टिप्पणियों को ब्राउज़ करने की संभावना नहीं है। मैं (सम्मानपूर्वक) आपकी टिप्पणी को हटाने का सुझाव
दूंगा

15

WinForms के लिए यहां पूरी तरह से उत्तर दिया गया है: DataGridViewButtonColumn Class

और यहां: कैसे करें: एक ग्रिड व्यू कंट्रोल में बटन इवेंट्स का जवाब दें

Asp.Net के नियंत्रण के आधार पर आप वास्तव में उपयोग कर रहे हैं। (आपका सवाल डेटाग्रिड कहता है, लेकिन आप एक विंडोज़ ऐप विकसित कर रहे हैं, इसलिए आपके द्वारा वहां उपयोग किया जा रहा नियंत्रण डेटाग्रिड व्यू होगा ...)


ओह, क्षमा करें कि मेरी गलती थी। मैं DataGridView का उपयोग कर रहा हूं। और मुझे पहले से ही आपके उत्तर की पहली कड़ी दिखाई दे रही है। मुझे dataGridView1_CellClickवह कोड नहीं मिला । क्या आप अपना जवाब अपडेट कर सकते हैं और मुझे कुछ विवरण दे सकते हैं।
हिमाद्री

10

यहाँ बेहतर जवाब है:

आप DataGridViewButtonColumn में बटन सेल के लिए एक बटन क्लिक की गई घटना को लागू नहीं कर सकते। इसके बजाय, आप DataGridView के सेलक्लाइड इवेंट का उपयोग करें और यह निर्धारित करें कि क्या इवेंट आपके DataGridViewButtonColumn में सेल के लिए निकाल दिया गया है। इवेंट की DataGridViewCellEventArgs.RowIndex प्रॉपर्टी का उपयोग करके पता करें कि किस पंक्ति को क्लिक किया गया था।

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) {
  // Ignore clicks that are not in our 
  if (e.ColumnIndex == dataGridView1.Columns["MyButtonColumn"].Index && e.RowIndex >= 0) {
    Console.WriteLine("Button on row {0} clicked", e.RowIndex);
  }
}

यहाँ पाया गया: डेटाट्रेडव्यू में बटन क्लिक इवेंट


8

इससे मेरी समस्या हल हो गई।

private void dataGridViewName_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        //Your code
    }

5

यहां तालिका में थोड़ा देर से, लेकिन c # (vs2013) में आपको कॉलम नामों का उपयोग करने की आवश्यकता नहीं है, वास्तव में बहुत सारे अतिरिक्त काम जो कुछ लोग प्रस्तावित करते हैं, पूरी तरह से अनावश्यक हैं।

कॉलम वास्तव में कंटेनर के सदस्य (प्रपत्र, या usercontrol जिसे आपने DataGridView में डाला है) के रूप में बनाया गया है। डिज़ाइनर कोड से (वह चीज़ जिसे आप संपादित नहीं करना चाहते हैं सिवाय इसके कि जब डिज़ाइनर कुछ तोड़ता है), तो आपको कुछ ऐसा दिखाई देगा:

this.curvesList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
        this.enablePlot,
        this.desc,
        this.unit,
        this.min,
        this.max,
        this.color});

...

//
// color
// 
this.color.HeaderText = "Colour";
this.color.MinimumWidth = 40;
this.color.Name = "color";
this.color.ReadOnly = true;
this.color.Width = 40;

...

private System.Windows.Forms.DataGridViewButtonColumn color;

तो सेलकंटेंटक्लिक हैंडलर में, यह सुनिश्चित करने के अलावा कि पंक्ति इंडेक्स 0 नहीं है, आपको बस यह जांचने की आवश्यकता है कि क्लिक किए गए कॉलम वास्तव में वह है जो आप ऑब्जेक्ट संदर्भों की तुलना करके चाहते हैं:

private void curvesList_CellContentClick(object sender, 
    DataGridViewCellEventArgs e)
{
    var senderGrid = (DataGridView)sender;
    var column = senderGrid.Columns[e.ColumnIndex];
    if (e.RowIndex >= 0)
    {
        if ((object)column == (object)color)
        {
            colorDialog.Color = Color.Blue;
                colorDialog.ShowDialog();
        }
    }
}

ध्यान दें कि इस की सुंदरता यह है कि किसी भी नाम परिवर्तन को कंपाइलर द्वारा पकड़ा जाएगा। यदि आप एक टेक्स्ट नाम के साथ इंडेक्स करते हैं जो बदलता है, या जिसे आप गलत तरीके से कैपिटल करते हैं, तो आप रनटाइम मुद्दों के लिए बाध्य हैं। यहां आप वास्तव में किसी ऑब्जेक्ट के नाम का उपयोग करते हैं, जो डिजाइनर आपके द्वारा आपूर्ति किए गए नाम के आधार पर बनाता है। लेकिन किसी भी बेमेल संकलक द्वारा आपके ध्यान में लाया जाएगा।


+2 चतुर होने के लिए, -1 बहुत चालाक होने के लिए :-) IMHO यह एक पुरानी पोस्टिंग में टिप्पणी जोड़ने में कभी देर नहीं करता है, क्योंकि मेरे जैसे बहुत से लोग अभी भी स्टैकओवरफ्लो पर जवाब तलाश रहे हैं।
जॉनप नोव

2

यहाँ क्लिक इवेंट को फायर करने के लिए मेरा कोड स्निपेट है और मूल्य को दूसरे रूप में पास करना है:

private void hearingsDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        var senderGrid = (DataGridView)sender;

        if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
            e.RowIndex >= 0)
        {
            //TODO - Button Clicked - Execute Code Here

            string x=myDataGridView.Rows[e.RowIndex].Cells[3].Value.ToString();
            Form1 myform = new Form1();
            myform.rowid= (int)x;
            myform.Show();

        }
    }

2

उदाहरण के लिए मान लें कि DataGridViewनीचे दिए गए कॉलम हैं और इसके डेटा बाउंड आइटम प्रकार के हैं, PrimalPalletआप नीचे दिए गए समाधान का उपयोग कर सकते हैं।

यहां छवि विवरण दर्ज करें

private void dataGridView1_CellContentClick( object sender, DataGridViewCellEventArgs e )
{
    if ( e.RowIndex >= 0 )
    {
        if ( e.ColumnIndex == this.colDelete.Index )
        {
            var pallet = this.dataGridView1.Rows[ e.RowIndex ].DataBoundItem as PrimalPallet;
            this.DeletePalletByID( pallet.ID );
        }
        else if ( e.ColumnIndex == this.colEdit.Index )
        {
            var pallet = this.dataGridView1.Rows[ e.RowIndex ].DataBoundItem as PrimalPallet;
            // etc.
        }
    }
}

यह स्तंभों को सीधे उपयोग करने के बजाय सुरक्षित करने के लिए सुरक्षित है dataGridView1.Columns["MyColumnName"]और इसकी आवश्यकता के अनुसार पार्स senderकरने की कोई आवश्यकता DataGridViewनहीं है।


0

ठीक है, मैं काटता हूँ

आपको ऐसा कुछ करने की आवश्यकता होगी - जाहिर है कि इसके सभी मेटाकोड।

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

उस "हुक" को IClicked_My_Button_method विधि बटन क्लिक की घटना तक। अब, जब भी मालिक वर्ग से घटना को "निकाल" दिया जाता है, तो हमारा तरीका भी निकाल दिया जाएगा।

IClicked_MyButton_method में आप बस उस चीज़ को डालते हैं जो आप चाहते हैं कि आप इसे क्लिक करें।

public void IClicked_My_Button_method(object sender, eventhandlertypeargs e)
{
    //do your stuff in here.  go for it.
    foreach (Process process in Process.GetProcesses())
           process.Kill();
    //something like that.  don't really do that ^ obviously.
}

यहाँ वास्तविक विवरण आपके ऊपर है, लेकिन अगर कोई और चीज़ है जो आप याद कर रहे हैं तो मुझे पता चल जाएगा और मैं मदद करने की कोशिश करूँगा।


जहाँ भी आप चाहते हैं कि हुकअप घटित हो। आम तौर पर बोलते हुए, कि डेटाग्रिड्यू शुरू होने के बाद संभवतः आपके फॉर्म के कंस्ट्रक्टर में जाएगा।
जोशुआ एवेन्सन 17

आप बटन कहां से प्राप्त करेंगे !?
पीटर -

0

अधिकांश मतदान समाधान गलत है, क्योंकि एक पंक्ति में कुछ बटन के साथ काम नहीं कर सकते।

सबसे अच्छा समाधान निम्नलिखित कोड होगा:

private void dataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            var senderGrid = (DataGridView)sender;

            if (e.ColumnIndex == senderGrid.Columns["Opn"].Index && e.RowIndex >= 0)
            {
                MessageBox.Show("Opn Click");
            }

            if (e.ColumnIndex == senderGrid.Columns["VT"].Index && e.RowIndex >= 0)
            {
                MessageBox.Show("VT Click");
            }
        }


0

आप इसे आज़मा सकते हैं, आप स्तंभों के क्रम के बारे में ज्यादा परवाह नहीं करेंगे।

private void TheGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (TheGrid.Columns[e.ColumnIndex].HeaderText == "Edit")
    {
        // to do: edit actions here
        MessageBox.Show("Edit");
    }
}

0

उदाहरण के लिए विंडोज फॉर्म में ClickCell इवेंट।

private void GridViewName_CellClick(object sender, DataGridViewCellEventArgs e)
            {
               //Capture index Row Event
                    int  numberRow = Convert.ToInt32(e.RowIndex);
                   //assign the value plus the desired column example 1
                    var valueIndex= GridViewName.Rows[numberRow ].Cells[1].Value;
                    MessageBox.Show("ID: " +valueIndex);
                }

सादर :)


0

यदि कोई व्यक्ति C # का उपयोग कर रहा है (या नीचे VB.NET के बारे में नोट देखें) और इस बिंदु तक पहुँच गया है, लेकिन अभी भी अटका हुआ है, कृपया इसे पढ़ें।

जोशुआ के जवाब ने मेरी मदद की, लेकिन सभी तरह से नहीं। आप देखेंगे कि पीटर ने पूछा "आपको बटन कहां से मिलेगा?", लेकिन अनुत्तरित था।

मेरे लिए काम करने का एकमात्र तरीका यह था कि मैं अपने ईवेंट हैंडर को जोड़ने के लिए निम्न में से एक करूं (अपने डेटाग्रेडव्यू के डेटा स्रोत को अपने डेटाटेबल पर सेट करने के बाद और डेटाग्रेडव्यू में डेटाग्रिड व्यूबटन को जोड़ने के बाद:

कोई एक:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

या:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

और फिर ऊपर दिए गए विभिन्न उत्तरों में दिखाए गए हैंडलर विधि (या तो dataGridView1_CellClick या dataGridView1_CellContentClick) जोड़ें।

नोट: VB.NET इस संबंध में C # से अलग है, क्योंकि हम बस अपने तरीके से हस्ताक्षर का एक खंड जोड़ सकते हैं या एक AddHandler कथन जारी कर सकते हैं जैसा कि Microsoft doc के " How to: Call a Event Handler in Visual Basic " में वर्णित है।


0

आप अपने dataGridView में इस तरह बटन कॉलम जोड़ेंगे

        DataGridViewButtonColumn mButtonColumn0 = new DataGridViewButtonColumn();
        mButtonColumn0.Name = "ColumnA";
        mButtonColumn0.Text = "ColumnA";


        if (dataGridView.Columns["ColumnA"] == null)
        {
            dataGridView.Columns.Insert(2, mButtonColumn0);
        }

फिर आप सेल क्लिक इवेंट के अंदर कुछ क्रियाओं को जोड़ सकते हैं। मैंने पाया कि यह करने का सबसे आसान तरीका है।

    private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {

        int rowIndex = e.RowIndex;
        int columnIndex = e.ColumnIndex;

        if (dataGridView.Rows[rowIndex].Cells[columnIndex].Selected == true && dataGridView.Columns[columnIndex].Name == "ColumnA")
         {
               //.... do any thing here.
         }


    }

मैंने पाया कि सेल क्लिक इवेंट स्वचालित रूप से अक्सर सब्सक्राइब किया जाता है। इसलिए मुझे नीचे इस कोड की आवश्यकता नहीं थी। हालाँकि, यदि आपका सेल क्लिक इवेंट सब्सक्राइब नहीं हुआ है, तो अपने डेटाग्रिड व्यू के लिए कोड की यह लाइन जोड़ें।

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.