HotDog's Blog

Hotdog (Robert Verpalen) about C# and vb.net

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

JanFebruary 2006Mar
SMTWTFS
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011

Articles

Archives

Topics

CONTACT

Fun but useful linkies

General

VS 2005

Wolfenstein ET

Wednesday, February 15, 2006 #

See the bottom of this post if you just want to see a quick solution ;-)


What's this about?
The new .net 2.0 datagridview is a great control and implementing custom columns is very easy, but doing so has a tricky setback: inherited fields and properties are not persisted. I'm sure this little oversight is something that will be mended soon enough, but it in the meantime the only solution seems to be to override the clone functionality. Don't know why precisely, but in the background there seems to be a lot of cloning of the columns and cell templates going on.
Now the easiest way would seem to use a memberwiseclone, but that gives other errors. Probably this is also the reason why the data is not persisted: the mentioned datagridview objects implement their own cloning functionality.


Example:
The quickest way to see how the values are not persisted is to create a testcolumn, eg:
Code Copy
public class ExampleColumn : DataGridViewTextBoxColumn
{
private int testprop;
[DefaultValue(0)]
public
int TestProperty
{
get { return testprop; }
set
{ testprop = value; }
}
}
If you add this code to your project and build that project, the column will automatically show up in the available columns in a datagridview. Add a datagridview to a form, select its properties, select Columns, open the collection editor (click the ... button) and add a column. Choose the examplecolumn type.
Now change the TestProperty value. Close the dialog window, open it again and check the value. It will be back to 0. This will also happen in runtime after eg a datasource is asigned. Your columns will be cloned and private fields will not be cloned.
Code Copy
public override object Clone()
{
ExampleColumn o = base.Clone() as ExampleColumn;
o.testprop = testprop;
return
o;
}

This will persist the property, but is very maintenance sensitive. Each new property/field would have to be added manually.


Resuable Solution
A more generic solution is to have a function set the child fields. Reflection to the rescue again :)

Code CopyHideScrollFull
public class CustomDataGridViewColumn : DataGridViewTextBoxColumn
{
//needs a using System.Reflection;
///
<summary>
///
Extends the basic cloned object by doing a member wise cloning
///
on all the child fields
///
</summary>
///
<param name="Original"></param>
///
<param name="BaseClonedObject"></param>
///
<returns></returns>
public
static object CloneFields(object Original, object BaseClonedObject)
{
Type t = BaseClonedObject.GetType();
foreach
(FieldInfo fi in t.GetFields(
BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Instance | BindingFlags.SetField | BindingFlags.GetField
| BindingFlags.DeclaredOnly
))
{
fi.SetValue(BaseClonedObject, fi.GetValue(Original));
}
return
BaseClonedObject;
}
// Example call in an Iclonable object
public
override object Clone()
{
return CloneFields(this, base.Clone());
}
}
. . .
What I do myself, is have the custom columns (same can be done for the cell templates) inherit from this one. Normally you'll inherit from the DataGridViewTextBoxColumn anyway, even when implementing custom controls, so you don't have to worry about any of this cloning stuff. If that is not an option, the function can still be called straight out, as shown in the example method call.
posted @ 6:18 AM