web-dev-qa-db-ja.com

Datagridviewのボタン列でクリックイベントを処理する方法は?

C#を使用してWindowsアプリケーションを開発しています。 DataGridViewを使用してデータを表示しています。その中にボタン列を追加しました。 DataGridViewのボタンでクリックイベントを処理する方法を知りたいです。

120
Himadri

DataGridViewにボタンを追加し、クリックされたときにコードを実行したい。
簡単です-次の手順に従ってください。

禁止事項:

まず、これが何をするかですNOT

ここでの他の回答のいくつかの提案を避け、ボタンがクリックされたかどうかを判断するために列インデックスまたは列名をハードコーディングするための MSDNのドキュメント によって提供されます。クリックイベントはグリッド全体に登録されるため、何らかの理由でボタンがクリックされたことを確認する必要がありますが、ボタンが特定の列名またはインデックスにあると想定してそうするべきではありません...もっと簡単な方法があります...

また、どのイベントを処理するかに注意してください。繰り返しますが、ドキュメントと多くの例がこれを間違っています。ほとんどの例は、発生する CellClick イベントを処理します。

セルのいずれかの部分がクリックされたとき。

...ただし、rowヘッダーがクリックされるたびに起動します。これには、単にe.RowIndex値が0より小さいかどうかを判断するために、余分なコードを追加する必要があります

代わりに、発生するのは CellContentClick のみです。

セル内のコンテンツがクリックされたとき

何らかの理由で、columnヘッダーもセル内の「コンテンツ」と見なされるため、以下でそれを確認する必要があります。

すべきこと:

だからあなたがすべきことは次のとおりです:

まず、cast送信者をDataGridViewと入力して、設計時に内部プロパティを公開します。パラメーターの型を変更できますが、ハンドラーの追加または削除が難しい場合があります。

次に、ボタンがクリックされたかどうかを確認するには、イベントを発生させる列のタイプが DataGridViewButtonColumn であることを確認します。送信者を既にDataGridView型にキャストしているため、Columnsコレクションを取得し、e.ColumnIndexを使用して現在の列を選択できます。次に、そのオブジェクトがDataGridViewButtonColumn型であるかどうかを確認します。

もちろん、グリッドごとに複数のボタンを区別する必要がある場合は、列名またはインデックスに基づいて選択できますが、これは最初のチェックではありません。常にボタンが最初にクリックされたことを確認してから、他のものを適切に処理してください。グリッドごとにボタンが1つしかないほとんどの場合、すぐにレースにジャンプできます。

すべてを一緒に入れて:

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でボタンがクリックされるたびに発生する独自のイベントを追加できます。継承などに煩わされることなく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 clickedDataGridViewを拡張するアプローチを次に示します。すべてのライブラリでカスタムコントロールを提供する手間をかける価値はないかもしれませんが、少なくともボタンがクリックされたかどうかを判断するために使用されるコードを最大限に再利用します。

これをアセンブリに追加するだけです:

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
225
KyleMit

WinFormsについては、ここで完全に回答されています。 DataGridViewButtonColumn Class

そしてここ: 方法:GridViewコントロールのボタンイベントに応答する

実際に使用しているコントロールに応じて、Asp.Netの場合。 (あなたの質問はDataGridですが、Windowsアプリを開発しているので、使用するコントロールにはDataGridViewがあります...)

15
David

より良い答えは次のとおりです。

DataGridViewButtonColumnのボタンセルにボタンクリックイベントを実装することはできません。代わりに、DataGridViewのCellClickedイベントを使用し、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);
  }
}

ここにあります: datagridviewのボタンクリックイベント

9
TechStuffBC

これは私の問題を解決します。

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

ここの表に少し遅れていますが、C#(vs2013)では列名を使用する必要もありません。実際、一部の人が提案する余分な作業の多くは完全に不要です。

列は、実際にはコンテナー(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;

したがって、CellContentClickハンドラーでは、行インデックスが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();
        }
    }
}

この美しさは、anyの名前の変更がコンパイラーによってキャッチされることに注意してください。テキスト名を変更してインデックスを作成するか、大文字を誤って使用すると、ランタイムの問題が発生します。ここでは、設計者が指定した名前に基づいて作成するオブジェクトの名前を実際に使用します。しかし、不一致はコンパイラによって注意を喚起されます。

4
Arunas

クリックイベントを発生させ、値を別のフォームに渡すためのコードスニペットを次に示します。

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
newComer

たとえば、DataGridViewに以下に示す列があり、そのデータバインドアイテムのタイプがPrimalPalletであると仮定すると、以下に示すソリューションを使用できます。

enter image description here

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"]を使用するよりも直接列にアクセスする方が安全です。また、senderDataGridViewに解析する必要はありません。

1
Ryfcia

ほとんどの投票されたソリューションは間違っています。1行のボタンが少ないと機能しないからです。

最善の解決策は次のコードです。

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
Andrew

たとえば、Windowsフォームの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);
                }

よろしく:)

これを試すことができますが、列の順序についてはあまり気にしません。

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

誰かがC#を使用している(または、以下のVB.NETに関する注意を参照)がこのポイントに達したが、まだ動かない場合は、先に進んでください。

ジョシュアの答えは私を助けましたが、すべてではありませんでした。ピーターは「どこからボタンを入手しますか?」と尋ねましたが、答えはありませんでした。

私にとって唯一の方法は、次のいずれかを実行してイベントハンドラーを追加することでした(DataGridViewのDataSourceをDataTableに設定し、DataGridViewButtonColumnをDataGridViewに追加した後)。

どちらか:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

または:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

次に、上記のさまざまな回答に示されているハンドラメソッド(dataGridView1_CellClickまたはdataGridView1_CellContentClick)を追加します。

注:VB.NETは、この点でC#とは異なります。これは、Microsoftのドキュメントの「 方法:Visualでイベントハンドラーを呼び出す基本 "

0
clairestreb

結構、噛みます。

あなたはこのような何かをする必要があります-明らかにそのすべてのメタコード。

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

iClicked_My_Button_methodメソッドをボタンのClickイベントまで「フック」します。これで、所有者クラス内からイベントが「起動」されるたびに、メソッドも起動されます。

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

ここで実際の詳細はあなた次第ですが、他に何か不足していることがあれば概念的に私に知らせてください、私は助けようとします。

0
Joshua Evensen

このようなボタン列を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.
         }


    }

Cell Clickイベントは自動的に頻繁にサブスクライブされることがわかりました。したがって、以下のこのコードは必要ありませんでした。ただし、セルクリックイベントがサブスクライブされていない場合は、dataGridViewにこのコード行を追加します。

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
0
auto9817

リストの最後にToList()メソッドを追加し、datagridview DataSourceにバインドします。

dataGridView1.DataSource = MyList.ToList();
0