2009-05-19 12 views
26

Ich habe eine Reihe von 'dynamischen Daten', die ich an das GridControl binden muss. Bis jetzt habe ich die Standard-DataTable-Klasse verwendet, die Teil des System.Data-Namespace ist. Das hat gut geklappt, aber mir wurde gesagt, dass ich das nicht verwenden kann, da es für die Serialisierung zwischen dem Client & Server zu schwer ist.Datenbindung dynamische Daten

Also dachte ich, ich könnte einfach eine "cut-down" Version der DataTable-Klasse replizieren, indem Sie einfach eine Art von List<Dictionary<string, object>>, wobei die Liste die Sammlung von Zeilen darstellt, und jedes Wörterbuch eine Zeile mit den Spaltennamen und Werten darstellt als KeyValuePair-Typ. Ich konnte das Gitter einrichten, um die Spalte Datafield Eigenschaften aufweisen, die denen der Schlüssel im Wörterbuch übereinstimmen (wie ich für die Datatable der Spaltennamen tat.

jedoch nach

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

Das Gitter hat zu tun keine Daten ...

ich glaube, ich brauche IEnumerator zu implementieren - jede Hilfe auf diesem würde geschätzt viel

Beispiel Aufruf Code sieht wie folgt aus:

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(); 
+0

GridControl? Meinst du DataGridView? –

Antwort

61

Willkommen in der wunderbaren Welt von System.ComponentModel. Diese dunkle Ecke von .NET ist sehr mächtig, aber sehr komplex.

Ein Wort der Vorsicht; es sei denn, Sie haben viel Zeit dafür - Sie können es gut tun, um es einfach in dem Mechanismus zu serialisieren, mit dem Sie glücklich sind, aber rehydrieren es wieder in ein DataTable an jedem Ende ... was folgt ist nicht für die Mutlosen; - p

Erstens - Datenbindung (für Tabellen) arbeitet gegen Listen (IList/IListSource) - so sollte List<T> in Ordnung sein (herausgegeben: ich falsch verstanden etwas). Aber es wird nicht verstehen, dass Ihr Wörterbuch tatsächlich Spalten ist ...

Um einen Typ zu erhalten, um Spalten zu haben, müssen Sie benutzerdefinierte PropertyDescriptor Implementierungen verwenden. Je nachdem, ob die Spaltendefinitionen immer gleich sind (aber zur Laufzeit bestimmt werden, d. H. Vielleicht von config), oder ob sie sich je nach Verwendung ändert (wie jede Instanz unterschiedliche Spalten haben kann), gibt es mehrere Möglichkeiten.

Für „pro Instanz“ Anpassung, müssen Sie bei ITypedList aussehen - dieses Tier (implementiert in zusätzlich-IList) präsentieren Eigenschaften für tabellarische Daten den Spaß Aufgabe hat ... aber es ist nicht allein:

für „pro Typ“ Anpassung können Sie bei TypeDescriptionProvider finden - diese dynamischen Eigenschaften für eine Klasse vorschlagen kann ...

... oder Sie können ICustomTypeDescriptor implementieren - aber dies ist nur (für Listen) in sehr gelegentliche Umstände (ein Objekt Indexer (public object this[int index] {get;} ") und mindestens eine Zeile in der Liste an der Bindungsstelle). (Diese Schnittstelle ist viel nützlicher beim Binden von diskreten Objekten - d. h. nicht von Listen).

Implementieren ITypedList, und ein PropertyDescriptor Modell ist harte Arbeit ... daher ist es nur sehr gelegentlich getan. Ich bin ziemlich vertraut damit, aber ich würde es nicht nur zum Lachen machen ...


hier eine sehr, sehr vereinfachte Implementierung (alle Spalten sind Strings, keine Benachrichtigungen (über Descriptor), keine Validierung (IDataErrorInfo), keine Konvertierungen (TypeConverter), keine zusätzliche Liste Unterstützung (IBindingList/IBindingListView) , keine Abstraktion (IListSource), keine anderen Metadaten/Attribute usw.):

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; 
     } 
    } 
} 
+0

Awesome Antwort Ich werde es loslassen lassen Sie wissen, wie ich komme ... –

+3

Autsch ... Meine Augen bluten. Ich gehe zurück zu den Sammlungen von Datensätzen und dynamischen Spalten: D – Larry

+1

@ControlBreak - lol; eine kluge Wahl, vermute ich. –