views:

2474

answers:

2

I am binding a List to a DataGridView. One property of the SomeObject class will be a status code (ex. Red, Yellow, Green). Can I "bind" the status to the background color of a cell easily? How about binding to a tooltip also?

+1  A: 

Out of the box, any DataGridViewColumn can be bound to only one property of the objects in the DataSource, the name of the property being given by the DataPropertyName of each DataGridViewColumn (you'll have specific column types like: DataGridViewTextBoxColumn, ...).

You could use the DataGridView.CellFormatting event to change the style of the cell depending on the databound item. In the In the DataGridViewCellFormattingEventArgs of this event you get the row index, from there you can get the current object (the source of the row). From there, you could use any property of the object to influence your cell.

A good starting point (similar idea): here

A second idea would be do develop your own DataGridViewColumn type and add properties for other things you need to bind to. For example, the same way it has the built in DataPropertyName, you could add your own: BackgroundColorPropertyName. A starting point for building custom DataGridViewColumns can be found here.

Sergiu Damian
+10  A: 

You can write a handler for the DataGridView's CellFormatting event to customise the background colour. Here's a worked example (you'll need to have dragged a DataGridView onto the default Form then double-clicked on the CellFormatting event to create a handler):

using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private BindingSource _source = new BindingSource();

        public Form1()
        {
            InitializeComponent();

            _source.Add(new MyData(Status.Amber, "Item A"));
            _source.Add(new MyData(Status.Red, "Item B"));
            _source.Add(new MyData(Status.Green, "Item C"));
            _source.Add(new MyData(Status.Green, "Item D"));

            dataGridView1.DataSource = _source;
            dataGridView1.Columns[0].Visible = false;
        }

        private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                DataGridView dgv = sender as DataGridView;
                MyData data = dgv.Rows[e.RowIndex].DataBoundItem as MyData;

                switch (data.Status)
                {
                    case Status.Green:
                        e.CellStyle.BackColor = Color.Green;
                        break;
                    case Status.Amber:
                        e.CellStyle.BackColor = Color.Orange;
                        break;
                    case Status.Red:
                        e.CellStyle.BackColor = Color.Red;
                        break;
                }
            }
        }
    }

    public class MyData
    {
        public Status Status { get; set; }
        public string Text { get; set; }

        public MyData(Status status, string text)
        {
            Status = status;
            Text = text;
        }
    }

    public enum Status
    {
        Green,
        Amber,
        Red
    }
}

The objects here just have a Status and Text for simplicity. I create a BindingSource for an example set of these objects, then use that as the data source for the DataGridView. By default, the grid automatically generates columns when you bind, so there's no need to do that manually. I also hide the first column, which is bound to the Status value, as we're going to colour the Text cells instead.

To actually do the painting, we respond to the CellFormatting event. We get a reference to the DataGridView by casting sender, then use the RowIndex property of the DataGridViewCellFormattingEventArgs object to get at the data item iteself (each Row has a DataBoundItem property that conveniently gives us this). As DataBoundItem is an object type, we need to cast it to our specific type, then we can actually get to the Status property itself...phew!

I haven't had any experience with tooltip programming, but I would have thought that you should respond to the MouseHover event, then work on discovering which row is being pointed at to start with.

I hope this helps.

Dave R.
Nice answer - thanks.
frou
+1, Great answer. I found the last row was an empty row, so had to check if MyData was null. Apart from that, great!
Russell