Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>i think this can be done by using a <code>TypeDescriptionProvider</code>.</p> <p><strike>the BAD news is: i have never done this before and won't be able to provide much help</strike></p> <p>the GOOD news is: i've found an example here: <a href="https://stackoverflow.com/questions/1468840/datagridview-not-showing-properites-of-objects-which-implement-icustomtypedescrip">DataGridView not showing properites of objects which implement ICustomTypeDescriptor</a></p> <p>//edit</p> <p>i used the code (see link above) to build an example how to avoid the dictionary per object ... </p> <pre><code>public class myRow { //your data storage class ... public string txt { get; set; } public int id { get; set; } } public class MyView:ICustomTypeDescriptor {//your extendable view class ... private static PropertyDescriptorCollection props = null; static MyView() { TypeDescriptionProvider defaultProvider = TypeDescriptor.GetProvider(typeof(MyView)); props = new PropertyDescriptorCollection(defaultProvider.GetTypeDescriptor(typeof(MyView)).GetProperties().Cast&lt;PropertyDescriptor&gt;().ToArray(), true); } public static void addProperty(string name, DataTable dt, Func&lt;DataRow, object&gt; getter, Action&lt;DataRow, object&gt; setter, Func&lt;DataTable, MyView, DataRow&gt; rowSelector, Type PropType) { List&lt;PropertyDescriptor&gt; tmp; if (props != null) tmp = props.Cast&lt;PropertyDescriptor&gt;().ToList(); else tmp = new List&lt;PropertyDescriptor&gt;(); PropertyDescriptor pd = TypeDescriptor.CreateProperty(typeof(MyView), name, PropType, null); pd = new MyViewPropertyDescriptor(pd, dt, getter, setter, rowSelector, PropType); tmp.Add(pd); props = new PropertyDescriptorCollection(tmp.ToArray(), true); } //the data storage obj this view is referencing public myRow obj; public string TXT { // view-member known at compile time get { return obj.txt; } set { obj.txt = value; } } internal class MyViewPropertyDescriptor : PropertyDescriptor { // an example property descriptor that can link to data in a DataTable ... DataTable dt; Func&lt;DataRow, object&gt; getter; Action&lt;DataRow, object&gt; setter; Func&lt;DataTable, MyView, DataRow&gt; rowSelector; Type type; public MyViewPropertyDescriptor(PropertyDescriptor descr, DataTable dt, Func&lt;DataRow, object&gt; getter, Action&lt;DataRow, object&gt; setter, Func&lt;DataTable, MyView, DataRow&gt; rowSelector, Type PropType) : base(descr) { this.dt = dt; // storage for additional data referenced by this property this.getter = getter; //a getter that will take a DataRow, and extract the property value this.setter = setter; //a setter that will take a DataRow and a value this.rowSelector = rowSelector;//a row selector ... takes a dataset and the view object and has to return the assiciated datarow this.type = PropType; // the type of this property } public override object GetValue(object component) { // using row selector and getter to return the current value ... you should add errorhandling here return getter(rowSelector(dt, (MyView)component)); } public override void SetValue(object component, object value) { // the setter ... needs errorhandling too setter(rowSelector(dt, (MyView)component), value); } public override void ResetValue(object component) { } public override bool CanResetValue(object component) { return false; } public override bool ShouldSerializeValue(object component) { return false; } public override Type PropertyType { get { return type; } } public override bool IsReadOnly { get { return false; } } public override Type ComponentType { get { return typeof(MyView); } } } ICustomTypeDescriptor defaultDescriptor = TypeDescriptor.GetProvider(typeof(MyView)).GetTypeDescriptor(typeof(MyView)); AttributeCollection ICustomTypeDescriptor.GetAttributes() { return defaultDescriptor.GetAttributes(); } string ICustomTypeDescriptor.GetClassName() { return defaultDescriptor.GetClassName(); } string ICustomTypeDescriptor.GetComponentName() { return defaultDescriptor.GetComponentName(); } TypeConverter ICustomTypeDescriptor.GetConverter() { return defaultDescriptor.GetConverter(); } EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { return defaultDescriptor.GetDefaultEvent(); } PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { return defaultDescriptor.GetDefaultProperty(); } object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return defaultDescriptor.GetEditor(editorBaseType); } EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { return defaultDescriptor.GetEvents(attributes); } EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { return defaultDescriptor.GetEvents(); } PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) { return props; // should really be filtered, but meh! } PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() { return props; } object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) { return this; } } </code></pre> <p>and a little example that makes use of this ...</p> <pre><code>private void button1_Click(object sender, EventArgs e) { if (dataGridView1.DataSource == null) { List&lt;myRow&gt; data = new List&lt;myRow&gt;(); data.Add(new myRow { id = 1, txt = "test 1" }); data.Add(new myRow { id = 2, txt = "test 2" }); data.Add(new myRow { id = 3, txt = "test 3" }); DataTable dt = new DataTable(); dt.Columns.Add("id", typeof(int)); dt.Columns.Add("additionalData1", typeof(int)); dt.Columns.Add("additionalData2", typeof(int)); Random rnd = new Random(); foreach (var item in data) { dt.Rows.Add(new object[] { item.id, rnd.Next(), rnd.Next() }); } MyView.addProperty("additionalData1", dt, row =&gt; row["additionalData1"], (row, val) =&gt; row["additionalData1"] = val, (tab, v) =&gt; tab.Rows.OfType&lt;DataRow&gt;().First(x =&gt; x["id"].Equals(v.obj.id)), typeof(int)); MyView.addProperty("additionalData2", dt, row =&gt; row["additionalData2"], (row, val) =&gt; row["additionalData2"] = val, (tab, v) =&gt; tab.Rows.OfType&lt;DataRow&gt;().First(x =&gt; x["id"].Equals(v.obj.id)), typeof(int)); dataGridView1.DataSource = new BindingList&lt;MyView&gt;(data.Select(x =&gt; new MyView { obj = x }).ToList()); } } </code></pre> <p>of course you will want to provide a better rowSelector or replace the DataTable with a Hashtable or whatever datastructure you want ... just an example</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload