web-dev-qa-db-ja.com

データバインディング動的データ

GridControlにバインドする必要のある「動的データ」のセットがあります。これまで、System.Data名前空間の一部である標準のDataTableクラスを使用してきました。これは正常に機能しましたが、クライアントとサーバー間のネットワーク全体でシリアル化するには重すぎるため、これを使用できないと言われました。

したがって、List<Dictionary<string, object>>のタイプを使用するだけで、DataTableクラスの「カットダウン」バージョンを簡単に複製できると思いました。これにより、リストは行のコレクションを表し、各ディクショナリは列名と値を持つ1つの行を表しますKeyValuePairタイプとして。 (DataTableの列名に対して行ったのと同じように)ディクショナリ内のキーのプロパティと一致するように列のDataFieldプロパティを持つようにグリッドを設定できます。

しかしやった後

gridControl.DataSource = table;
gridControl.RefreshDataSource();

グリッドにはデータがありません...

私はIEnumeratorを実装する必要があると思います-これに関する助けがあれば大歓迎です!

呼び出しコードの例は次のようになります。

var table = new List<Dictionary<string,object>>();

var row = new Dictionary<string, object>
{
    {"Field1", "Data1"},
    {"Field2", "Data2"},
    {"Field3", "Data3"}
};

table.Add(row);

gridControl1.DataSource = table;
gridControl1.RefreshDataSource();
27
Chris Moutray

System.ComponentModelの素晴らしい世界へようこそ。 .NETのこの暗いコーナーは非常に強力ですが、非常に複雑です。

注意の言葉;これに多くの時間がない限り、満足のいくメカニズムで単純にシリアル化するのがよいかもしれませんが、両端でDataTableに再水和します...以下は気弱な;-p

まず、(テーブルの)データバインディングはlistsIList/IListSource)に対して機能します-so List<T>は問題ないはずです(編集:私は何かを読み間違えました)。しかし、あなたの辞書が実際には列であることを理解するつもりはありません...

列を持つふりをする型を取得するには、カスタムPropertyDescriptor実装を使用する必要があります。これを行うには、列の定義が常に同じであるか(ただし、実行時に、つまり構成から決定されるか)、または使用ごとに変更されるか(各DataTableインスタンスがどのように異なるかなど)に応じて、いくつかの方法があります。列)。

「インスタンスごと」のカスタマイズについては、ITypedListを確認する必要があります-この獣(additionIListに実装されています)表形式のデータのプロパティを表示するという楽しいタスクがあります...しかし、それだけではありません。

「タイプごと」のカスタマイズについては、TypeDescriptionProviderを確認できます。これはクラスの動的プロパティを示唆している可能性があります。

...またはICustomTypeDescriptorを実装できますが、これは(リストの場合)非常に時折の状況(オブジェクトインデクサー(public object this[int index] {get;} ")およびバインドの時点でリスト内の少なくとも1つの行)(このインターフェイスは、個別のオブジェクトをバインドする場合、つまりリストではない場合にはるかに便利です)。

ITypedListの実装、およびPropertyDescriptorモデルの提供は大変な作業です...したがって、それはごくまれにしか行われません。私はそれをかなりよく知っていますが、笑いのためだけにそれをするつもりはありません...


これが非常に単純化された実装(すべての列は文字列です。通知なし(記述子経由)、検証なし(IDataErrorInfo)、変換なし(TypeConverter)、いいえ追加のリストサポート(IBindingList/IBindingListView)、抽象化なし(IListSource)、その他のメタデータ/属性など):

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

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        PropertyBagList list = new PropertyBagList();
        list.Columns.Add("Foo");
        list.Columns.Add("Bar");
        list.Add("abc", "def");
        list.Add("ghi", "jkl");
        list.Add("mno", "pqr");

        Application.Run(new Form {
            Controls = {
                new DataGridView {
                    Dock = DockStyle.Fill,
                    DataSource = list
                }
            }
        });
    }
}
class PropertyBagList : List<PropertyBag>, ITypedList
{
    public PropertyBag Add(params string[] args)
    {
        if (args == null) throw new ArgumentNullException("args");
        if (args.Length != Columns.Count) throw new ArgumentException("args");
        PropertyBag bag = new PropertyBag();
        for (int i = 0; i < args.Length; i++)
        {
            bag[Columns[i]] = args[i];
        }
        Add(bag);
        return bag;
    }
    public PropertyBagList() { Columns = new List<string>(); }
    public List<string> Columns { get; private set; }

    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        if(listAccessors == null || listAccessors.Length == 0)
        {
            PropertyDescriptor[] props = new PropertyDescriptor[Columns.Count];
            for(int i = 0 ; i < props.Length ; i++)
            {
                props[i] = new PropertyBagPropertyDescriptor(Columns[i]);
            }
            return new PropertyDescriptorCollection(props, true);            
        }
        throw new NotImplementedException("Relations not implemented");
    }

    string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
    {
        return "Foo";
    }
}
class PropertyBagPropertyDescriptor : PropertyDescriptor
{
    public PropertyBagPropertyDescriptor(string name) : base(name, null) { }
    public override object GetValue(object component)
    {
        return ((PropertyBag)component)[Name];
    }
    public override void SetValue(object component, object value)
    {
        ((PropertyBag)component)[Name] = (string)value;
    }
    public override void ResetValue(object component)
    {
        ((PropertyBag)component)[Name] = null;
    }
    public override bool CanResetValue(object component)
    {
        return true;
    }
    public override bool ShouldSerializeValue(object component)
    {
        return ((PropertyBag)component)[Name] != null;
    }
    public override Type PropertyType
    {
        get { return typeof(string); }
    }
    public override bool IsReadOnly
    {
        get { return false; }
    }
    public override Type ComponentType
    {
        get { return typeof(PropertyBag); }
    }
}
class PropertyBag
{
    private readonly Dictionary<string, string> values
        = new Dictionary<string, string>();
    public string this[string key]
    {
        get
        {
            string value;
            values.TryGetValue(key, out value);
            return value;
        }
        set
        {
            if (value == null) values.Remove(key);
            else values[key] = value;
        }
    }
}
63
Marc Gravell