C# grid DataSource polymorphism

前端 未结 7 1715
我在风中等你
我在风中等你 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条回答
  • 2021-01-06 06:58

    Data-binding to lists follows the following strategy:

    1. does the data-source implement IListSource? if so, goto 2 with the result of GetList()
    2. does the data-source implement IList? if not, throw an error; list expected
    3. does the data-source implement ITypedList? if so use this for metadata (exit)
    4. does the data-source have a non-object indexer, public Foo this[int index] (for some Foo)? if so, use typeof(Foo) for metadata
    5. is there anything in the list? if so, use the first item (list[0]) for metadata
    6. no metadata available

    List<IListItem> falls into "4" above, since it has a typed indexer of type IListItem - and so it will get the metadata via TypeDescriptor.GetProperties(typeof(IListItem)).

    So now, you have three options:

    • write a TypeDescriptionProvider that returns the properties for IListItem - I'm not sure this is feasible since you can't possibly know what the concrete type is given just IListItem
    • use the correctly typed list (List<User> etc) - simply as a simple way of getting an IList with a non-object indexer
    • write an ITypedList wrapper (lots of work)
    • use something like ArrayList (i.e. no public non-object indexer) - very hacky!

    My preference is for using the correct type of List<>... here's an AutoCast method that does this for you without having to know the types (with sample usage);

    Note that this only works for homogeneous data (i.e. all the objects are the same), and it requires at least one object in the list to infer the type...

    // infers the correct list type from the contents
    static IList AutoCast(this IList list) {
        if (list == null) throw new ArgumentNullException("list");
        if (list.Count == 0) throw new InvalidOperationException(
              "Cannot AutoCast an empty list");
        Type type = list[0].GetType();
        IList result = (IList) Activator.CreateInstance(typeof(List<>)
              .MakeGenericType(type), list.Count);
        foreach (object obj in list) result.Add(obj);
        return result;
    }
    // usage
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        List<IListItem> data = new List<IListItem> {
            new User { Id = "1", Name = "abc", UserSpecificField = "def"},
            new User { Id = "2", Name = "ghi", UserSpecificField = "jkl"},
        };
        ShowData(data, "Before change - no UserSpecifiedField");
        ShowData(data.AutoCast(), "After change - has UserSpecifiedField");
    }
    static void ShowData(object dataSource, string caption) {
        Application.Run(new Form {
            Text = caption,
            Controls = {
                new DataGridView {
                    Dock = DockStyle.Fill,
                    DataSource = dataSource,
                    AllowUserToAddRows = false,
                    AllowUserToDeleteRows = false
                }
            }
        });
    }
    
    0 讨论(0)
提交回复
热议问题