Làm cách nào để xử lý sự kiện nhấp trong Cột nút trong Datagridview?


136

Tôi đang phát triển một ứng dụng windows bằng C #. Tôi đang sử dụng DataGridViewđể hiển thị dữ liệu. Tôi đã thêm một cột nút trong đó. Tôi muốn biết làm thế nào tôi có thể xử lý sự kiện nhấp vào nút đó trong DataGridView.


1
Bạn đang thêm nút lập trình (như tôi nghi ngờ là cách duy nhất)?
XstreamINsanity

Có rất nhiều câu trả lời có sẵn cho trực tuyến này. Điều gì mang đến cho bạn rắc rối đặc biệt?
Joshua Evensen

1
@Joshua Tôi có nhiều câu trả lời trên mạng nhưng thực sự không biết phải làm gì và khi nào bắt đầu. Tôi đã thêm một nút trong datagridview của mình chỉ không biết cách xử lý sự kiện nhấp chuột của nó.
Himadri

Câu trả lời:


263

Bạn đã thêm một nút cho bạn DataGridViewvà bạn muốn chạy một số mã khi nhấp vào.
Dễ dàng dễ dàng - chỉ cần làm theo các bước sau:

Không:

Đầu tiên, đây là những gì KHÔNG nên làm:

Tôi sẽ tránh các đề xuất trong một số câu trả lời khác ở đây và thậm chí được cung cấp bởi tài liệu tại MSDN để mã hóa chỉ mục cột hoặc tên cột để xác định xem có nhấp vào nút không. Sự kiện nhấp đăng ký cho toàn bộ lưới, vì vậy bằng cách nào đó bạn cần xác định rằng một nút đã được nhấp, nhưng bạn không nên làm như vậy bằng cách giả sử rằng nút của bạn nằm trong một tên hoặc chỉ mục cột cụ thể ... có một cách dễ dàng hơn ...

Ngoài ra, hãy cẩn thận những sự kiện bạn muốn xử lý. Một lần nữa, các tài liệu và nhiều ví dụ nhận được điều này sai. Hầu hết các ví dụ xử lý CellClicksự kiện sẽ kích hoạt:

khi bất kỳ phần nào của một ô được bấm.

... nhưng cũng sẽ kích hoạt bất cứ khi nào tiêu đề hàng được nhấp. Điều này đòi hỏi phải thêm mã bổ sung đơn giản để xác định xem e.RowIndexgiá trị nhỏ hơn 0

Thay vào đó xử lý những CellContentClickgì chỉ xảy ra:

khi nội dung trong một ô được bấm

Vì bất kỳ lý do gì, tiêu đề cột cũng được coi là "nội dung" trong một ô, vì vậy chúng tôi vẫn phải kiểm tra phần bên dưới.

Liều dùng:

Vì vậy, đây là những gì bạn nên làm:

Đầu tiên, bỏ người gửi để nhập DataGridViewđể hiển thị các thuộc tính bên trong của nó tại thời điểm thiết kế. Bạn có thể sửa đổi loại trên tham số, nhưng điều đó đôi khi có thể khiến việc thêm hoặc xóa trình xử lý trở nên khó khăn.

Tiếp theo, để xem nếu một nút được nhấp, chỉ cần kiểm tra để đảm bảo rằng cột nâng sự kiện là loại DataGridViewButtonColumn. Vì chúng tôi đã chọn người gửi để nhập DataGridView, chúng tôi có thể lấy Columnsbộ sưu tập và chọn cột hiện tại bằng cách sử dụng e.ColumnIndex. Sau đó kiểm tra xem đối tượng đó có thuộc loại không DataGridViewButtonColumn.

Tất nhiên, nếu bạn cần phân biệt giữa nhiều nút trên mỗi lưới, thì bạn có thể chọn dựa trên tên hoặc chỉ mục của cột, nhưng đó không phải là kiểm tra đầu tiên của bạn. Luôn đảm bảo rằng một nút được nhấp trước và sau đó xử lý mọi thứ khác một cách thích hợp. Trong hầu hết các trường hợp bạn chỉ có một nút duy nhất cho mỗi lưới, bạn có thể nhảy ngay vào các cuộc đua.

Để tất cả chúng cùng nhau:

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

Cập nhật 1 - Sự kiện tùy chỉnh

Nếu bạn muốn có một chút niềm vui, bạn có thể thêm sự kiện của riêng mình để được nâng lên bất cứ khi nào một nút được nhấp vào DataGrid. Bạn không thể thêm nó vào DataGrid, mà không bị lộn xộn với tính kế thừa, v.v., nhưng bạn có thể thêm một sự kiện tùy chỉnh vào biểu mẫu của mình và kích hoạt nó khi thích hợp. Đó là một mã nhiều hơn một chút, nhưng nhược điểm là bạn đã tách ra những gì bạn muốn làm khi một nút được nhấp với cách xác định nếu một nút được nhấp.

Chỉ cần tuyên bố một sự kiện, nâng cao nó khi thích hợp và xử lý nó. Nó sẽ trông giống thế này:

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

Cập nhật 2 - Lưới mở rộng

Điều tuyệt vời là nếu chúng ta làm việc với một mạng lưới vừa làm những điều này cho chúng ta. Chúng tôi có thể trả lời câu hỏi ban đầu một cách dễ dàng : you've added a button to your DataGridView and you want to run some code when it's clicked. Đây là một cách tiếp cận mở rộng DataGridView. Nó có thể không có giá trị rắc rối khi phải cung cấp một điều khiển tùy chỉnh với mọi thư viện, nhưng ít nhất nó sử dụng tối đa mã được sử dụng để xác định nếu một nút được nhấp.

Chỉ cần thêm nó vào hội đồng của bạn:

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

Đó là nó. Không bao giờ chạm vào nó một lần nữa. Đảm bảo DataGrid của bạn thuộc loại DataGridViewExtsẽ hoạt động chính xác như DataGridView. Ngoại trừ nó cũng sẽ đưa ra một sự kiện bổ sung mà bạn có thể xử lý như thế này:

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

1
Trong VB.net, bạn không phải kiểm tra chỉ mục cột. Tôi đang sử dụng ví dụ chính xác này cho một dgv có hai cột. Một cột có thể chỉnh sửa và cột thứ 2 có loại bỏ mông. Tôi nhấp vào tất cả các dgv và sự kiện chỉ tắt khi tôi nhấp vào nút.
Sáng

3
+1. Tuy nhiên, trong trường hợp của chúng tôi, cột là một DataGridViewColumn chung và tôi đã phải kiểm tra loại ô:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
Dave Johnson

Đánh giá từ upvotes và bình luận Tôi hiểu đây là một câu trả lời đúng, nhưng ... tại sao mọi thứ phải luôn phức tạp như vậy! Tôi chưa tiếp cận WPF, nhưng liệu nó có giống như vậy không?
jj_

1
Mã C # cho Cập nhật 2public 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); } } }
Tony Cheetham

@tonyenkiducx, được đánh giá cao nhưng các nhận xét không thực sự là một nơi tốt để hiển thị cú pháp thay thế cho toàn bộ lớp, đặc biệt là một cú pháp có thể dễ dàng bắt nguồn thông qua trình chuyển đổi mã . Chắc chắn, mọi người sẽ đến đây để tìm kiếm c #, nhưng họ có thể tự băng qua đó và không có khả năng duyệt các bình luận đang tìm cách thực hiện. Tôi sẽ (trân trọng) đề nghị xóa bình luận của bạn
KyleMit

15

Điều đó đã được trả lời đầy đủ ở đây cho WinForms: Lớp DataGridViewButtonColumn

và tại đây: Cách: Trả lời các Sự kiện Nút trong Điều khiển GridView

cho Asp.Net tùy thuộc vào điều khiển bạn thực sự sử dụng. (Câu hỏi của bạn nói DataGrid, nhưng bạn đang phát triển ứng dụng Windows, do đó, kiểm soát bạn đang sử dụng có DataGridView ...)


Ồ, xin lỗi đó là sai lầm của tôi. Tôi đang sử dụng DataGridView. Và tôi đã thấy liên kết đầu tiên của câu trả lời của bạn. Tôi đã không nhận được dataGridView1_CellClicktrong mã đó. Bạn có thể cập nhật câu trả lời của bạn và cho tôi một số mô tả.
Himadri

10

Đây là câu trả lời tốt hơn:

Bạn không thể triển khai một sự kiện được nhấp vào nút cho các ô của nút trong DataGridViewButtonColumn. Thay vào đó, bạn sử dụng sự kiện CellClicky của DataGridView và xác định xem sự kiện đó có được kích hoạt cho một ô trong DataGridViewButtonColumn của bạn không. Sử dụng thuộc tính DataGridViewCellEventArss.RowIndex của sự kiện để tìm ra hàng nào được nhấp.

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

tìm thấy ở đây: nút bấm sự kiện trong datagridview


8

Điều này giải quyết vấn đề của tôi.

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

5

Một chút muộn để bàn ở đây, nhưng trong c # (vs2013), bạn không cần phải sử dụng tên cột, trong thực tế, rất nhiều công việc phụ mà một số người đề xuất là hoàn toàn không cần thiết.

Cột thực sự được tạo như một thành viên của bộ chứa (biểu mẫu hoặc điều khiển người dùng mà bạn đã đặt DataGridView vào). Từ mã nhà thiết kế (những thứ bạn không cần phải chỉnh sửa trừ khi nhà thiết kế phá vỡ thứ gì đó), bạn sẽ thấy một cái gì đó như:

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;

Vì vậy, trong trình xử lý CellContentClick, ngoài việc đảm bảo chỉ số hàng không bằng 0, bạn chỉ cần kiểm tra xem cột được nhấp có thực sự là cột bạn muốn hay không bằng cách so sánh các tham chiếu đối tượng:

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

Lưu ý rằng cái hay của việc này là bất kỳ thay đổi tên nào cũng sẽ bị trình biên dịch bắt gặp. Nếu bạn lập chỉ mục với một tên văn bản thay đổi hoặc viết hoa không chính xác, bạn bị ràng buộc cho các vấn đề thời gian chạy. Ở đây bạn thực sự sử dụng tên của một đối tượng, mà nhà thiết kế tạo ra dựa trên tên bạn đã cung cấp. Nhưng bất kỳ sự không phù hợp sẽ được trình biên dịch chú ý đến bạn.


+2 vì thông minh, -1 vì quá thông minh :-) IMHO không bao giờ là quá muộn để thêm nhận xét vào bài đăng cũ, bởi vì nhiều người như tôi vẫn đang tìm kiếm câu trả lời trên stackoverflow.
JonP

2

Đây là đoạn mã của tôi để kích hoạt sự kiện nhấp và chuyển giá trị sang dạng khác:

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

Ví dụ, giả sử DataGridViewcó các cột như được đưa ra dưới đây và các mục ràng buộc dữ liệu của nó thuộc loại PrimalPalletbạn có thể sử dụng giải pháp được đưa ra dưới đây.

nhập mô tả hình ảnh ở đây

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

Đó là an toàn hơn để cột truy cập trực tiếp hơn là sử dụng dataGridView1.Columns["MyColumnName"]và không có nhu cầu để phân tích senderđến DataGridViewkhi nó không cần thiết.


0

tốt thôi, tôi sẽ cắn.

bạn sẽ cần phải làm một cái gì đó như thế này - rõ ràng là tất cả siêu dữ liệu của nó.

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

rằng "móc nối" phương thức IClicky_My_Button_method cho đến sự kiện Click của nút. Bây giờ, mỗi khi sự kiện được "bắn" từ bên trong lớp chủ sở hữu, phương thức của chúng tôi cũng sẽ bị hủy.

Trong IClicky_MyButton_method, bạn chỉ cần đặt bất cứ điều gì bạn muốn xảy ra khi bạn nhấp vào nó.

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

Các chi tiết thực tế ở đây tùy thuộc vào bạn, nhưng nếu có bất cứ điều gì khác bạn đang thiếu về mặt khái niệm hãy cho tôi biết và tôi sẽ cố gắng giúp đỡ.


bất cứ nơi nào bạn muốn hookup đó xảy ra. Nói chung, điều đó có thể sẽ xuất hiện trong hàm tạo của biểu mẫu của bạn sau khi datagridview được khởi tạo.
Joshua Evensen

Bạn sẽ lấy nút từ đâu!?
Peter - Phục hồi Monica

0

Hầu hết các giải pháp được bình chọn là sai, vì không thể làm việc với một vài nút trong một hàng.

Giải pháp tốt nhất sẽ là đoạn mã sau:

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

chỉ cần thêm ToList()phương thức vào cuối danh sách của bạn, nơi liên kết với datagridview DataSource:

dataGridView1.DataSource = MyList.ToList();

0

Bạn có thể thử cái này, bạn sẽ không quan tâm nhiều đến thứ tự của các cột.

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

0

Ví dụ cho sự kiện ClickCell trong Windows Forms.

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

Trân trọng :)


0

Trong trường hợp ai đó đang sử dụng C # (hoặc xem Lưu ý về VB.NET bên dưới) và đã đạt đến điểm này, nhưng vẫn bị kẹt, vui lòng đọc tiếp.

Câu trả lời của Joshua đã giúp tôi, nhưng không phải là tất cả. Bạn sẽ nhận thấy Peter hỏi "Bạn sẽ lấy nút từ đâu?", Nhưng không được trả lời.

Cách duy nhất nó hoạt động với tôi là thực hiện một trong những cách sau để thêm trình xử lý sự kiện của tôi (sau khi đặt DataSource của DataGridView cho DataTable của tôi và sau khi thêm DataGridViewButtonColumn vào DataGridView):

Hoặc:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

hoặc là:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

Và sau đó thêm phương thức xử lý (dataGridView1_CellClick hoặc dataGridView1_CellContentClick) được hiển thị trong các câu trả lời khác nhau ở trên.

Lưu ý: VB.NET khác với C # về mặt này, vì chúng ta chỉ cần thêm mệnh đề Handles vào chữ ký của phương thức hoặc đưa ra câu lệnh AddHandler như được mô tả trong tài liệu " Cách gọi: Trình xử lý sự kiện trong Visual Basic " của tài liệu Microsoft


0

Bạn sẽ thêm cột nút như thế này trong dataGridView của bạn

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


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

Sau đó, bạn có thể thêm một số hành động bên trong sự kiện nhấp chuột di động. Tôi thấy đây là cách dễ nhất để làm điều đó.

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


    }

Tôi thấy rằng sự kiện Cell Click được đăng ký tự động thường xuyên. Vì vậy, tôi không cần mã này dưới đây. Tuy nhiên, nếu sự kiện nhấp vào ô của bạn không được đăng ký, thì hãy thêm dòng mã này cho dataGridView của bạn.

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.