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;
}
}
}
GridControl? Meinst du DataGridView? –