17

I'm trying to add a clickable image/button to a datagridview button column.

The image/button will be an icon for play or stop. If the user clicks the play button a service on the system is started, if the user clicks the stop button a service is stopped.

I already have written functions for starting and stopping the service. What I'm having difficulty with is getting the button/image to show up in the datagrid and making it clickable.

Here's what I have for code:

this.dgrdServices.RowPrePaint +=new DataGridViewRowPrePaintEventHandler(dgv_RowPrePaint);
this.dgrdServices.Rows.Add();
this.dgrdServices.Rows[0].Cells[0].Value = Image.FromFile(@"C:\users\brad\desktop\green-dot.gif"); 
this.dgrdServices.Rows[0].Cells[1].Value = "MyServer";
this.dgrdServices.Rows[0].Cells[2].Value = "MyService";
this.dgrdServices.Rows[0].Cells[3].Value = "Started";
this.dgrdServices.Rows[0].Cells[4].Value = new DataGridViewButtonCell();
this.dgrdServices.Rows[0].Cells[5].Value = "Uninstall";

I can't work out if it would be better to use a button which is an image or an just an image that's clickable. I also can't get a button to show up correctly.

Thanks Brad

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Brad
  • 1,979
  • 7
  • 35
  • 47
  • http://www.codeproject.com/KB/grid/DGV_ImageButtonCell.aspx – MethodMan Mar 27 '16 at 23:09
  • So, when you say it is not showing up correctly, is it just not showing up at all? Is it showing, but there is something wrong with the display? – Jace Mar 27 '16 at 23:09
  • 1
    I've tried various bits of code from examples I can find. I either end up with an unlabeled grey button, or a grey button which says windows.system.bitmap on it. Also I can't work out when the button is pressed to call my function which starts/stops the service. – Brad Mar 27 '16 at 23:22
  • Adding the image as a resource to the project may help. Are you actually declare the column as a dgv button column? You're not showing that in your code anywhere.Also from experience, if you have a 1000+ rows the images are going to make the DGV loading slow to a crawl – Michael Mar 27 '16 at 23:26
  • @MethodMan - I've seen that example. I couldn't work out how to get it working and it seems to be creating a new class based on an existing class. This seems overly complex. Surely there must be a more straightforward way to do this? – Brad Mar 27 '16 at 23:26
  • @michael - I added a datatview grid control to my winforms application then in the properties created a column with a column type of DataGridViewButtonColumn. As far as worrying about 1000+ rows - that's not a worry. At most the datagrid might have 10 rows - and that's an extreme. – Brad Mar 27 '16 at 23:29

1 Answers1

41

Show Image On Button

You can add a DataGridViewButtonColumn, then handle CellPainting event of the grid and check if the event is raised for your button column, then draw an image on it. At the end of event, don't forget to set e.Handled = true;.

In the below code I suppose you have an image resource like someImage:

private void grid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.RowIndex < 0)
        return;

    //I supposed your button column is at index 0
    if (e.ColumnIndex == 0)
    {
        e.Paint(e.CellBounds, DataGridViewPaintParts.All);

        var w = Properties.Resources.SomeImage.Width;
        var h = Properties.Resources.SomeImage.Height;
        var x = e.CellBounds.Left + (e.CellBounds.Width - w) / 2;
        var y = e.CellBounds.Top + (e.CellBounds.Height - h) / 2;

        e.Graphics.DrawImage(someImage, new Rectangle(x, y, w, h));
        e.Handled = true;
    }
}

Show Image Without Button

To show a single image on all rows including new row, you can set the Image property of DataGridViewImageColumn. This way the image will be shown in that column on for all rows:

dataGridView1.Columns.Add(new DataGridViewImageColumn(){
    Image = someImage, Name = "someName", HeaderText = "Some Text"
});

Also if you may want to have different images for cells, you can set the formatted value of DataGridViewImageColumn in CellFormatting event:

void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (e.RowIndex < 0)
        return;

    //I supposed the image column is at index 1
    if (e.ColumnIndex == 1)
        e.Value = someImage;
}

You also can set Image property of DataGridViewImageColumn to an image, but the image will not show on new row.

Handle Click

To handle Click on image/button you can handle CellClick or CellContentClick event:

void grid_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex < 0)
        return;

    //I suposed you want to handle the event for column at index 1
    if (e.ColumnIndex == 1)
        MessageBox.Show("Clicked!");
}

If you handled CellContentClick you should exactly click on image when you are using image column.

Screenshot

Here is the result. First column is a button column showing an image and second column is a normal image column set to show a single image:

enter image description here

Important Note

In above examples I assume you have an image in someImage member variable:

Image someImage = Properties.Resources.SomeImage

Make sure you dispose someImage on disposal of the form and avoid using Properties.Resources.SomeImage directly everywhere you need.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • I got this working but a couple comments - now I see a button with an image on top of it. What I really want to see is only the image. The image needs to be clickable though. – Brad Mar 28 '16 at 03:01
  • It is a button column which shows an image which you were looking for *I'm trying to add a clickable image/button to a datagridview button column.* – Reza Aghaei Mar 28 '16 at 03:04
  • 1
    If you only want an image, you can simply use a `DataGridViewImageColumn`. – Reza Aghaei Mar 28 '16 at 03:06
  • 1
    Also to handle click on button, it's enough to handle `CellContentClick` of grid. – Reza Aghaei Mar 28 '16 at 03:08
  • Getting this error trying to implement an image. Error 1 Property or indexer 'System.Windows.Forms.DataGridViewCellPaintingEventArgs.Value' cannot be assigned to -- it is read only and e.Value has a red squiggle underneath it. – Brad Mar 28 '16 at 13:50
  • @Brad Probably you mistakenly copied the code of `CellFormating` event to `CellPainting`. Carefully follow the answer, the screenshot has taken from execution of codes. And let me know the result :) – Reza Aghaei Mar 28 '16 at 14:45