Search code examples
.netwinformsdatagridviewcastle-activerecord

DataGridView, BindingList<T>, DataGridViewComboBoxColumn


So, I have a DataGridView using as datasource a BindingList

DataGridView.DataSource = new  BindingList<Car>{...}

Where

public class Car
{
    public ColorName Color { get; set;}
}

with

public class ColorName
{
    public int Id {get; set;}
    public string Name{get; set;}
}

and I use a Combobox column:

DataGridViewComboBoxColumn colorNameDataGridViewTextBoxColumn;
colorNameDataGridViewTextBoxColumn.DataPropertyName = "Color";
colorNameDataGridViewTextBoxColumn.HeaderText = "Color";
colorNameDataGridViewTextBoxColumn.Name = "Color";
colorNameDataGridViewTextBoxColumn.DisplayMember = "Name";
colorNameDataGridViewTextBoxColumn.ValueMember = "Id";
colorNameDataGridViewTextBoxColumn.DataSource = new ColorName[] {...};

How can I get this to work ?! Now I get an exception because I think it tries to cast the Id to ColorName.

I tried with an empty ValueMember or adding a direct cast operator to ColorName class but can't get it to work.

Sure I can use an int in the Car class to represent the color but is not as nice.

As you probably guessed those classes are in fact Castle Project ActiveRecord-s.

Any ideas are welcome !


Solution

  • Did you try ValueMember = "" or ValueMember = "."?

    Really hacky, but you could add a property on ColorName that is itself? (perhaps via a partial class)

    public ColorName Self {get {return this;}}
    

    then set `ValueMember = "Self";'

    Other than that, you'd probably need a TypeConverter

    The other option might be to override ToString() on ColorName to return Name, and not have a value/display member?


    (update: no it doesn't)

    Have checked, and ToString() seems to work :

    public override string ToString() { return Name; }
    

    and just don't set a DisplayMember or a ValueMember.


    Well whad'ya know - the "Self" trick works too ...

    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    class ColorName
    {
        public ColorName(int id, string name) {
            this.Id = id;
            this.Name = name;
        }
        public int Id { get; private set; }
        public string Name { get; private set; }
    
        // maybe declare this one in a partial class...
        public ColorName Self { get { return this; } }
    }
    class Car
    {
        public ColorName Color { get; set; }
    }
    
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            using(Form form = new Form())
            using (DataGridView grid = new DataGridView())
            {
                grid.Dock = DockStyle.Fill;
                grid.AutoGenerateColumns = false;
                ColorName[] colors = new[] {
                  new ColorName(1,"Red"),
                  new ColorName(2,"Blue"),
                  new ColorName(3,"Green")
                };
                var col = new DataGridViewComboBoxColumn
                {
                    DataPropertyName = "Color",
                    HeaderText = "Color",
                    Name = "Color",
                    DisplayMember = "Name",
                    ValueMember = "Self",
                    DataSource = colors
                };
    
                grid.Columns.Add(col);
                grid.DataSource = new BindingList<Car> {
                    new Car { Color = colors[0]}
                };
                form.Controls.Add(grid);
                Application.Run(form);
            }
        }
    }