1

カスタムタイプをバインドしたい(たとえば、実行時に入力されるプロパティまたはデータを使用)。コンパイル時のプロパティの数がわからないので、それらを含むリストを作成する必要があります。

後で、このオブジェクトを含むリストをグリッドまたはDropDownListにバインドしたいと思います。

これらのコントロールは、DataSourceプロパティを介してDataSource(オブジェクト)を受け取ることを知っています。メソッドDataBind()を呼び出すと、デフォルトの実装はリフレクションを使用してプロパティとデータを取得し、そのコントロールに書き込みます。

私にはタイプがあります、想像してみましょう:

class MyDynamicDataObject {
Dictionary<string, object> _properties;

public MyDynamicDataObject() {
    _properties = new Dictionary<string, object>();
}

public void Add(string property, object value) {
    _properties.Add(property, value);   
}

}

しかし、_propertiesディクショナリのデータ構造に含まれている私のタイプのプロパティを「オーバーライド」するか、抽象的な方法で返すことを知っておく必要があります。

これを実行して、コントロールでDataBindを使用し、デフォルトの実装を使用できるようにするにはどうすればよいですか(Type.GetPropertiesを使用)。ただし、noneの型プロパティを返す代わりに、ディクショナリに含まれている抽象化を返しますか?

ありがとう

4

2 に答える 2

2

ほとんどのデータバインディングはすでに動的データモデルをサポートしていますが、データモデルはサポートしていませんdynamic。つまり、これには、、ICustomTypeDescriptor(おそらくを介してTypeDescriptionProvider) 、、、などの既存のメカニズムがITypedListありPropertyDescriptorます。DataTableこれは、と同様に使用されるメカニズムであるため、十分に実行されます。リストにバインドしているので、ITypedList実装するのにおそらく最も適切なインターフェースです。つまりPropertyDescriptor、ディクショナリAPIと記述子APIの間でマップするカスタムを作成する必要があります。

これがwinformsの例です:

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

static class Program
{
    [STAThread]
    static void Main()
    {
        using(var form = new Form())
        using(var grid = new DataGridView())
        {
            var list = new MySpecialList();
            var obj = new MyDynamicDataObject();
            obj["Foo"] = 123;
            obj["Bar"] = "def";
            list.Add(obj);
            obj = new MyDynamicDataObject();
            obj["Bar"] = "abc";
            obj["Blap"] = 123.4F;
            list.Add(obj);

            grid.DataSource = list;
            grid.Dock = DockStyle.Fill;
            form.Controls.Add(grid);
            Application.Run(form);
        }
    }
}
class MySpecialList : List<MyDynamicDataObject>, ITypedList
{
    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        // don't worry about sub-property access unless you need to
        if(listAccessors != null && listAccessors.Length != 0) throw new NotSupportedException();

        var allKeys = new HashSet<string>();
        foreach(var item in this)
        {
            foreach (string key in item.GetKeys()) allKeys.Add(key);
        }
        var props = allKeys.Select(key => new MyDynamicDataObjectDescriptor(key));
        return new PropertyDescriptorCollection(props.ToArray());
    }
    private class MyDynamicDataObjectDescriptor : PropertyDescriptor
    {
        public MyDynamicDataObjectDescriptor(string name) : base(name, new Attribute[0]) { }

        public MyDynamicDataObject GetObject(object component)
        {
            return (MyDynamicDataObject) component;
        }
        public override object GetValue(object component)
        {
            return GetObject(component)[Name];
        }
        public override void SetValue(object component, object value)
        {
            GetObject(component)[Name] = value;
        }
        public override bool CanResetValue(object component)
        {
            return false;
        }
        public override void ResetValue(object component)
        {
            throw new NotSupportedException();
        }
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
        public override bool IsReadOnly
        {
            get { return false; }
        }
        public override Type ComponentType
        {
            get { return typeof (MyDynamicDataObject); }
        }
        public override Type PropertyType
        {
            get { return typeof (object); }
        }
    }

    string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
    {
        throw new System.NotImplementedException();
    }
}
class MyDynamicDataObject
{
    // don't recommend inheriting this; confuses matters a lot...
    private Dictionary<string,object> props = new Dictionary<string, object>();
    public string[] GetKeys()
    {
        return props.Keys.ToArray();
    }
    public void Clear(string key)
    {
        props.Remove(key);
    }
    public object this[string key]
    {
        get
        {
            object value;
            if (!props.TryGetValue(key, out value)) value = null;
            return value;
        }
        set
        {
            props[key] = value;
        }
    }
}
于 2012-06-29T09:23:35.667 に答える
1
 public interface IDynamicObject
{
    string[] Properties { get; }
    void Clear();
    object this[string property] { get; set; }
}



public class DynamicObject : IDynamicObject
{
    readonly Dictionary<string, object> _dynamicProperties = new Dictionary<string, object>();

    public string[] Properties
    {
        get { return _dynamicProperties.Keys.ToArray(); }
    }

    public void Clear() { _dynamicProperties.Clear(); }

    public object this[string property]
    {
        get
        {
            object value;

            if (!_dynamicProperties.TryGetValue(property, out value))
                value = null;

            return value;
        }

        set
        {
            _dynamicProperties[property] = value;
        }
    }
}



public class DynamicObjectPropertyDescriptor<T> : PropertyDescriptor
    where T : IDynamicObject
{
    public DynamicObjectPropertyDescriptor(string name) : base(name, new Attribute[0])
    {

    }



    T Get(object component)
    {
        return (T)component;
    }



    public override bool IsReadOnly                                  { get { return false; } }
    public override bool CanResetValue(object component)             { return true; }
    public override void ResetValue(object component)                { Get(component)[Name] = null; }

    public override Type ComponentType                               { get { return typeof(T); } }
    public override Type PropertyType                                { get { return typeof(object); } }

    public override object  GetValue(object component)               { 
        return Get(component)[Name];
    }
    public override void    SetValue(object component, object value) { 
        Get(component)[Name] = value; 
    }

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



public class DynamicList<T> : List<T>, ITypedList 
    where T : IDynamicObject
{
    int bindingIndex = 0;


    public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        if (listAccessors != null && listAccessors.Length != 0)
            throw new NotSupportedException();

        if (Count == 0)
            return new PropertyDescriptorCollection(new[] { new DynamicObjectPropertyDescriptor<T>("-") });

        PropertyDescriptorCollection result = new PropertyDescriptorCollection(this[bindingIndex].Properties.Select(prop => new DynamicObjectPropertyDescriptor<T>(prop)).ToArray());

        if (++bindingIndex == Count)
            bindingIndex = 0;

        return result;
    }

    public string GetListName(PropertyDescriptor[] listAccessors)
    {
        return typeof(DynamicList<T>).Name;
    }
}

これが機能することを確認するには:

DynamicList<DynamicObject> list = new DynamicList<DynamicObject>();

        DynamicObject a1 = new DynamicObject();

        a1["nome"] = "Goncalo Dias";
        a1["numero"] = 30337;


        DynamicObject a2 = new DynamicObject();

        a2["nome"] = "Carlos Antunes";
        a2["numero"] = 10222;


        DynamicObject a3 = new DynamicObject();

        a3["nome"] = "Tiago Rodrigues";
        a3["numero"] = 4040;

        DynamicObject a4 = new DynamicObject();

        a4["nome"] = "Digoo Martins";
        a4["numero"] = 1220;
        a4["morada"] = "Rua da esquina";

        list.Add(a1);
        list.Add(a2);
        list.Add(a3);
        list.Add(a4);


        ultraGrid1.DataSource = list;
        ultraGrid1.DataBind();
于 2012-06-29T14:13:18.210 に答える