Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
249 views
in Technique[技术] by (71.8m points)

c# - How does one bind a complex object to a DataGridView?

I have a class that follows the form:

public class Cat
{
    public string Name { get; set; }
    public string Description {get; set; }
    public List<Cheezburger> Cheezbugers { get; private set; }
};

public class Cheezburger
{
    public int PattyCount { get; set; }
    public bool CanHaz { get; set; }
};

I want to be able to display a List of Cats this in a DataGridView as follows:

---------------------------------------------------------------------------------
| Name     | Description  |  PattyCount | CanHaz   | PattyCount   | CanHaz  | etc
--------------------------------------------------------------------------------
| Felix    | Classic Cat  |  1          | true     | 3            | false   | etc
| Garfield | Fat,Lazy Cat |  2          | false    | 7            | true    | etc

And so on... The goal being to list out all the Cat's Cheezbugers in the same row. If you simply try binding the list of Cats you won't get this behavior.

The problem is that I can't figure out how to do a do a complex binding of source between the DataGridView and the individual items in the list of Cats.Cheezbugers. For what its worth, I know for sure that each Cat in the list has the same number of Cheezbugers in its list.

Edit:

I am aware that DataGridView complex binding asks the same question, but the accepted answer works only if I know how many items are in the list ahead of time, and that is not the case. All I know is that all the lists will have the same length.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This isn't just a 'complex binding' this is a Pivot, where you are wanting to transform detail repeating data (the list o' cheezburgers) to a single row, and that row has an undetermined number of columns.

I believe your best option here is to write a custom serializer that will allow you to transform your data into rows in an xml datatable and then bind to that. Since your column count is going to be inconsistent xml will be more forgiving, though I am not sure how the DataGridView will handle it.

EDIT FOLLOWS Since I did not 'know' how the DataGridView would handle the XML DataTable I decided to write it up and test it. I works how I expected, and I believe how you will want.

  1. Here are your cat & cheezburger classes (slightly modified)

    public class Cat
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public List<Cheezburger> Cheezbugers { get; private set; }
    
        public void AddCheezburger(Cheezburger cheezburger)
        {
            if (this.Cheezbugers == null)
                this.Cheezbugers = new List<Cheezburger>();
            this.Cheezbugers.Add(cheezburger); 
        }
    };
    
    public class Cheezburger
    {
        public int PattyCount { get; set; }
        public bool CanHaz { get; set; }
    };
    
  2. Then you need to create simple form with two buttons "bind to object" (button1) and "bind to datatable" (button2), with a DataGridView anchored to the bottom. and code up the form like:

//in the editor this next line is in the codeblock, once I save it it isn't..

public partial class Form1 : Form
{

    List<Cat> cats = new List<Cat>();

    public Form1()
    {
        InitializeComponent();

        cats.Add(new Cat() { Name = "Felix", Description = "Classic Cat" });
        cats.Add(new Cat() { Name = "Garfield", Description = "Fat,Lazy" });
        cats.Add(new Cat() { Name = "Tom", Description = "Wanna-Be-Mouser" });
        cats[0].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 1 });
        cats[0].AddCheezburger(new Cheezburger() { CanHaz = false, PattyCount = 3 });
        cats[1].AddCheezburger(new Cheezburger() { CanHaz = false, PattyCount = 2 });
        cats[1].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 7 });
        cats[1].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 99 });
        cats[2].AddCheezburger(new Cheezburger() { CanHaz = true, PattyCount = 5 });
        cats[2].AddCheezburger(new Cheezburger() { CanHaz = false, PattyCount = 14 });

    }

    private void button1_Click(object sender, EventArgs e)
    {
        dataGridView1.DataSource = null;
        dataGridView1.DataSource = cats;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        dataGridView1.DataSource = null;
        dataGridView1.DataSource = serializeCats(cats);
    }

    private DataTable serializeCats(List<Cat> cats)
    {

        DataTable returnTable = new DataTable("Cats");
        returnTable.Columns.Add(new DataColumn("Name"));
        returnTable.Columns.Add(new DataColumn("Description"));
        int setID = 1;
        foreach (Cat cat in cats)
        {
            //If the row requires more columns than are present then add additional columns
            int totalColumnsRequired = (cat.Cheezbugers.Count * 2) + 2;

            while (returnTable.Columns.Count < totalColumnsRequired)
            {
                returnTable.Columns.Add(new DataColumn("Can Haz " + setID.ToString()));
                returnTable.Columns.Add(new DataColumn("Patty Count " + setID.ToString()));
                setID++;
            }
            returnTable.AcceptChanges();
            DataRow row = returnTable.NewRow();
            row[0] = cat.Name;
            row[1] = cat.Description;
            int cbi = 2; //cheezburger index
            foreach (Cheezburger cheezburger in cat.Cheezbugers)
            {
                row[cbi] = cheezburger.CanHaz;
                cbi++;
                row[cbi] = cheezburger.PattyCount;
                cbi++;
            }

            returnTable.Rows.Add(row);
        }
        return returnTable;
    }
}

Do not attempt to predefine the DataGridView columns, they will be created dynamically based on the data source. Binding to the list of cats will get you two columns (name/description) Binding to the DataTable gets 8 columns, name & description + 6 columns of cheezburger info, lined up as (I believe) you want. Cats Haz Cheezeburgers


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...