简体   繁体   中英

Displaying a list of object containing a list in a grid view

I am currently working on a bookmark manager application (Windows Forms), with advanced search capabilities.

I have created a Links class, and every time a user enters a URL, I'll create a Link object and store the details there. It currently has the properties Name , URL and Tags , where Tags is a list.

At runtime when I set the DataSource property of a gridview to the List<Links> objects, the Name and the URL show up but the tags do not .

How do I go about displaying the list of tags inside the List<Links> object in the gridview?

EDIT: Just had an idea. What if I write a function to convert the List<Links> into a DataTable , and then set the DataSource property of the DataGrid to the DataTable ?

The problem with this is that everytime a change is made to the List<Links> I will have to generate the DataTable again, which does not seem ideal from a performance point of view.

EDIT 2: I wish to display each item in the list as a DataGridViewTextBox column.

Thanks,

Abijeet.

Maybe this is what you want... an object that appears to have more properties that it actually has.

The DataGridView controll supports the ComponentModel namespace so that you can create classes that appear to have properties that don't exist. It is the same mechanism the PropertyGrid uses.

Sample code

This sample is a fully working windows forms class, with a form containing a DataGridView . I add some objects to is, using a list that is then set to the DataSource property.

The objects inside that list, have no properties at all... but they use component model to describe 'virtual' properties to the DataGridView .

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.dataGridView1.Dock = DockStyle.Fill;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            dataGridView1.DataSource = new List<MyClass>
                    {
                      new MyClass("value 1", "value 2", "value 3"),
                      new MyClass("value 1", "value 2"),
                    };
        }

        class MyClass : CustomTypeDescriptor
        {
            public MyClass(params string[] tags)
            {
                this.tags = new List<string>(tags);
            }

            public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                var listProps = new List<PropertyDescriptor>();

                // adding properties dynamically
                for (int i = 0; i < tags.Count; i++)
                    listProps.Add(new PropDesc("Tag" + i, i));

                return new PropertyDescriptorCollection(listProps.ToArray());
            }

            private List<string> tags = new List<string>();

            class PropDesc : PropertyDescriptor
            {
                private int index;

                public PropDesc(string propName, int index)
                    : base(propName, new Attribute[0])
                {
                    this.index = index;
                }

                public override bool CanResetValue(object component) { return false; }

                public override Type ComponentType { get { return typeof(MyClass); } }

                public override object GetValue(object component)
                {
                    if (index >= ((MyClass)component).tags.Count)
                        return null;

                    return ((MyClass)component).tags[index];
                }

                public override bool IsReadOnly { get { return true; } }

                public override Type PropertyType { get { return typeof(string); } }

                public override void ResetValue(object component) { }

                public override void SetValue(object component, object value) { }

                public override bool ShouldSerializeValue(object component) { return false; }
            }
        }

        private void InitializeComponent()
        {
            this.dataGridView1 = new DataGridView();
            ((ISupportInitialize)(this.dataGridView1)).BeginInit();
            this.SuspendLayout();
            // dataGridView1
            this.dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Dock = DockStyle.Fill;
            this.dataGridView1.Location = new System.Drawing.Point(0, 0);
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.Size = new System.Drawing.Size(284, 262);
            this.dataGridView1.TabIndex = 1;
            // Form1
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 262);
            this.Controls.Add(this.dataGridView1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((ISupportInitialize)(this.dataGridView1)).EndInit();
            this.ResumeLayout(false);

        }

        private DataGridView dataGridView1;
    }
}

If you are working in WPF, as I think you do, why not use the DataGridView Row Detail Template? You can have a second grid as the row's detail template which you bind with the tags list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM