C# grid DataSource polymorphism

前端 未结 7 1754
我在风中等你
我在风中等你 2021-01-06 06:28

I have a grid, and I\'m setting the DataSource to a List. What I want is to have the list bind to the underlying type, and disply

7条回答
  •  梦毁少年i
    2021-01-06 06:40

    As long as you know for sure that the members of the List are all going to be of the same derived type, then here's how to do it, with the "Works on my machine" seal of approval.

    First, download BindingListView, which will let you bind generic lists to your DataGridViews.

    For this example, I just made a simple form with a DataGridView and randomly either called code to load a list of Users or Locations in Form1_Load().

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;
    using Equin.ApplicationFramework;
    
    namespace DGVTest
    {
        public interface IListItem
        {
            string Id { get; }
            string Name { get; }
        }
    
        public class User : IListItem
        {
            public string UserSpecificField { get; set; }
            public string Id { get; set; }
            public string Name { get; set; }
        }
    
        public class Location : IListItem
        {
            public string LocationSpecificField { get; set; }
            public string Id { get; set; }
            public string Name { get; set; }
        }
    
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void InitColumns(bool useUsers)
            {
                if (dataGridView1.ColumnCount > 0)
                {
                    return;
                }
    
                DataGridViewCellStyle gridViewCellStyle = new DataGridViewCellStyle();
    
                DataGridViewTextBoxColumn IDColumn = new DataGridViewTextBoxColumn();
                DataGridViewTextBoxColumn NameColumn = new DataGridViewTextBoxColumn();
                DataGridViewTextBoxColumn DerivedSpecificColumn = new DataGridViewTextBoxColumn();
    
                IDColumn.DataPropertyName = "ID";
                IDColumn.HeaderText = "ID";
                IDColumn.Name = "IDColumn";
    
                NameColumn.DataPropertyName = "Name";
                NameColumn.HeaderText = "Name";
                NameColumn.Name = "NameColumn";
    
                DerivedSpecificColumn.DataPropertyName = useUsers ? "UserSpecificField" : "LocationSpecificField";
                DerivedSpecificColumn.HeaderText = "Derived Specific";
                DerivedSpecificColumn.Name = "DerivedSpecificColumn";
    
                dataGridView1.Columns.AddRange(
                    new DataGridViewColumn[]
                        {
                            IDColumn,
                            NameColumn,
                            DerivedSpecificColumn
                        });
    
                gridViewCellStyle.SelectionBackColor = Color.LightGray;
                gridViewCellStyle.SelectionForeColor = Color.Black;
                dataGridView1.RowsDefaultCellStyle = gridViewCellStyle;
            }
    
            public static void BindGenericList(DataGridView gridView, List list)
            {
                gridView.DataSource = new BindingListView(list);
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                dataGridView1.AutoGenerateColumns = false;
    
                Random rand = new Random();
    
                bool useUsers = rand.Next(0, 2) == 0;
    
                InitColumns(useUsers);
    
                if(useUsers)
                {
                    TestUsers();
                }
                else
                {
                    TestLocations();
                }
    
            }
    
            private void TestUsers()
            {
                List items =
                    new List
                        {
                            new User {Id = "1", Name = "User1", UserSpecificField = "Test User 1"},
                            new User {Id = "2", Name = "User2", UserSpecificField = "Test User 2"},
                            new User {Id = "3", Name = "User3", UserSpecificField = "Test User 3"},
                            new User {Id = "4", Name = "User4", UserSpecificField = "Test User 4"}
                        };
    
    
                BindGenericList(dataGridView1, items.ConvertAll(item => (User)item));
            }
    
            private void TestLocations()
            {
                List items =
                    new List
                        {
                            new Location {Id = "1", Name = "Location1", LocationSpecificField = "Test Location 1"},
                            new Location {Id = "2", Name = "Location2", LocationSpecificField = "Test Location 2"},
                            new Location {Id = "3", Name = "Location3", LocationSpecificField = "Test Location 3"},
                            new Location {Id = "4", Name = "Location4", LocationSpecificField = "Test Location 4"}
                        };
    
    
                BindGenericList(dataGridView1, items.ConvertAll(item => (Location)item));
            }
        }
    }
    

    The important lines of code are these:

    DerivedSpecificColumn.DataPropertyName = useUsers ? "UserSpecificField" : "LocationSpecificField"; // obviously need to bind to the derived field
    
    public static void BindGenericList(DataGridView gridView, List list)
    {
        gridView.DataSource = new BindingListView(list);
    }
    
    dataGridView1.AutoGenerateColumns = false; // Be specific about which columns to show
    

    and the most important are these:

    BindGenericList(dataGridView1, items.ConvertAll(item => (User)item));
    BindGenericList(dataGridView1, items.ConvertAll(item => (Location)item));
    

    If all items in the list are known to be of the certain derived type, just call ConvertAll to cast them to that type.

提交回复
热议问题