Extending the DataGrid

C

Colin Young

I'm using the ExtendedDataGrid (an extension to the standard datagrid
available in the workspaces at www.gotdotnet.com) but I've got a problem I'd
like to see if I can find a solution to.

Basically it provides (among other things) a calculated column where you can
place C# code that will be executed at runtime so you can do things like
display values that are calculated from the current row values. The problem
is if you want to do a calculation and display the columns the calculation
is based on, you can't because the calculated column needs to have a valid
MappingName that isn't already in use and exists. I think this limitation is
due to the underlying datagrid. Is there some way I can create some code to
allow me to specify a non-existant MappingName and still have the column
appear?

Thanks

Colin
 
Y

Ying-Shen Yu[MSFT]

Hi Colin,

From my understanding, you need add a calculated column to your datagrid
instead of replacing an existing one, right?

To use a column style on datagrid, we need set the MappingName for the
ColumnStyle, however you may add an unbounded column to the underlying data
table, then bind the calculate column style to this column. Here is an
sample in SyncFusion WinForm FAQ, you may try it to see if it resolves your
problem.
http://www.syncfusion.com/FAQ/WinForms/FAQ_c44c.asp#q787q

Please feel free to reply this thread, if you still have problem on this
issue.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
C

Colin Young

That doesn't exactly solve my problem. It isn't convenient for me to add
extra columns to my datasource. I need to be able to use the same column
multiple times in the datagrid. In addition to being able to perform
calculations on the columns, I also need to display all the columns used in
the calculation in the datagrid. Currently that isn't possible.

e.g. I need to display quantity, cost and quantity * cost and those are all
the columns in the datasource. I can't set the MappingName to cost or
quantity because they are already in use. If I add a calculated column to
the underlying datasource that would solve my problem, but I can't be
recompiling and redistributing the application every time somebody wants to
change the calculation (currently the column uses dynamic compilation to
perform the calculations).

Thanks.

Colin
 
J

John Saunders

The Expression property of the DataColumn class is a string. You could pull
the string from a configuration file, so you wouldn't have to recompile your
application in order to change the expression.

Also, you say that it's not convenient for you to add columns to the data
source. Do you mind if I ask why not? Perhaps the data source belongs to
another piece of code and you don't want to change it?
--
John Saunders
John.Saunders at SurfControl.com

Colin Young said:
That doesn't exactly solve my problem. It isn't convenient for me to add
extra columns to my datasource. I need to be able to use the same column
multiple times in the datagrid. In addition to being able to perform
calculations on the columns, I also need to display all the columns used in
the calculation in the datagrid. Currently that isn't possible.

e.g. I need to display quantity, cost and quantity * cost and those are all
the columns in the datasource. I can't set the MappingName to cost or
quantity because they are already in use. If I add a calculated column to
the underlying datasource that would solve my problem, but I can't be
recompiling and redistributing the application every time somebody wants to
change the calculation (currently the column uses dynamic compilation to
perform the calculations).

Thanks.

Colin

"Ying-Shen Yu[MSFT]" said:
Hi Colin,

From my understanding, you need add a calculated column to your datagrid
instead of replacing an existing one, right?

To use a column style on datagrid, we need set the MappingName for the
ColumnStyle, however you may add an unbounded column to the underlying data
table, then bind the calculate column style to this column. Here is an
sample in SyncFusion WinForm FAQ, you may try it to see if it resolves your
problem.
http://www.syncfusion.com/FAQ/WinForms/FAQ_c44c.asp#q787q

Please feel free to reply this thread, if you still have problem on this
issue.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
C

Colin Young

John Saunders said:
The Expression property of the DataColumn class is a string. You could pull
the string from a configuration file, so you wouldn't have to recompile your
application in order to change the expression.

That's what I plan to do. I'm not having trouble with this part.
Also, you say that it's not convenient for you to add columns to the data
source. Do you mind if I ask why not? Perhaps the data source belongs to
another piece of code and you don't want to change it?

That's exactly what it is. I'm not using a dataset, but a collection of
custom business objects, so it would be a matter of adding dummy properties
to the business objects, and I would need to know in advance how many dummy
properties would be needed by the display code. This approach will result in
non-obvious coupling between the business logic and display code.
Additionally, the objects are automatically generated (by a product called
LLBLGen) so it would require a bit more work to derive extra object
inheriting from the generated object which will just add to the confusion.

The best solution would be if I can find a way to get the datagrid to
generate the extra column even if the property referred to by the
MappingName property doesn't exist.

Colin
 
Y

Ying-Shen Yu[MSFT]

Hi Colin,

Base on my knowledge the datagrid class in .NET framework only support
bounded columnstyles, if adding an extra column to the underlying
datasource is not an option, you may try some 3rd party datagrid components
which supports unbound columns instead. (Xceed Grid, syncfusion's Essential
grid etc).

Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
C

Colin Young

If that is the case then perhaps you could suggest to the development team
that they provide support for adding unbound columns. It seems to me that it
shouldn't be that difficult to do.

I've looked into the third-party grids and so far they are too expensive for
this project (and contain far too many features) in addition to being much
more difficult to work with.

Colin
 
Y

Ying-Shen Yu[MSFT]

Hi Colin,

I have forwarded your feedback to our product group.
Since the 3rd party components are not suitable for you, then is it
possible to add some "wrapper" class to workaround this issue?
I mean write two wrapper class for your collection class and your business
object class, then add extra properties on the wrapper class for business
object.

In the Item property of the collection wrapper class, return the wrapper
object for the business object,then bound your collection to datagrid like
dataGrid1.DataSource = new CollectionWrapper(businessCollectionObject);

Does this way resolve your problem?
Feel free to reply this thread if you have anything unclear on it.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
C

Colin Young

That's what I'm working on doing. The big problem is that I don't know in
advance how many extra properties I might need, so I am going to need to
either limit the UI layer to a fixed set of properties exposed by the object
or add a bunch of dummy properties (i.e. Unbound1, Unbound2, Unbound3, ...)
and hope I've provided enough for any reasonable UI display.

Colin
 
Y

Ying-Shen Yu[MSFT]

Hi Colin,


Defining a bunch of dummy properties seems like the simplest way to work
around this issue. If you really need a more flexible solution, You may
implement the ICustomTypeDescriptor interface on your wrapper class for the
business object, in the GetProperties method, return the properties on the
business object and add the dummy properties on your need (this
can be changed even in run-time), however it's might be a bit overkill for
your needs.
You may find many samples on how implement an ICustomTypeDescriptor
interface on CodeProject, here is one of which:
<Customized display of collection data in a PropertyGrid>
http://www.codeproject.com/cs/miscctrl/customizingcollectiondata.asp
It's of a different topic, however it will show you how to implement the
interface.

Does it fit your needs?
Feel free to reply this thread, if you have anything unclear about this
issue.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
C

Colin Young

I'm not sure if I've looked at that example or not (the site isn't
accessible for me right now). I tried to implement the ICustomTypeDescriptor
interface, but I couldn't figure out how to return a property (I just need
to return a dummy string for any of the new properties I add). Does that
example show how to return a dummy property, or can you provide a link that
shows how?

In my case implementing that interface would be easier because my objects
are generated from a template and this would allow me to add the dummy
properties to all my objects at once.

Thanks

Colin
 
Y

Ying-Shen Yu[MSFT]

Hi Colin,

Here is a simple sample for adding a dummy property into the
PropertyCollection.
<code>
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace _DesignTime__ICustomTypeDescriptor_
{
/// <summary>
/// Summary description for UserControl1.
/// </summary>
public class UserControl1 :
System.Windows.Forms.UserControl,ICustomTypeDescriptor
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public UserControl1()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();

// TODO: Add any initialization after the InitializeComponent call

}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion

#region ICustomTypeDescriptor Members

public TypeConverter GetConverter()
{
// TODO: Add UserControl1.GetConverter implementation
return null;
//return TypeDescriptor.GetConverter(this);
}

public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
// TODO: Add UserControl1.GetEvents implementation
return TypeDescriptor.GetEvents(this,attributes,true);
}

EventDescriptorCollection
System.ComponentModel.ICustomTypeDescriptor.GetEvents()
{
// TODO: Add
UserControl1.System.ComponentModel.ICustomTypeDescriptor.GetEvents
implementation
return TypeDescriptor.GetEvents(this,null,true);
}

public string GetComponentName()
{
// TODO: Add UserControl1.GetComponentName implementation
return TypeDescriptor.GetComponentName(this,true);
}

public object GetPropertyOwner(PropertyDescriptor pd)
{
// TODO: Add UserControl1.GetPropertyOwner implementation
if (pd == null)
return this;
else return pd.GetValue(GetPropertyOwner(pd));
}

public AttributeCollection GetAttributes()
{
// TODO: Add UserControl1.GetAttributes implementation
//return TypeDescriptor.GetAttributes(this,true);
//need return an empty collectiom
return TypeDescriptor.GetAttributes(this,true);
}

public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
// TODO: Add UserControl1.GetProperties implementation
return ((ICustomTypeDescriptor)this).GetProperties();
}

PropertyDescriptorCollection
System.ComponentModel.ICustomTypeDescriptor.GetProperties()
{
// TODO: Add
UserControl1.System.ComponentModel.ICustomTypeDescriptor.GetProperties
implementation
PropertyDescriptorCollection col =
TypeDescriptor.GetProperties(this,null,true);

ArrayList props = new ArrayList(col);
props.Add(new DummyPropertyDescriptor("Dummy"));
PropertyDescriptorCollection newCol = new PropertyDescriptorCollection(
(PropertyDescriptor[])props.ToArray(typeof(PropertyDescriptor)));

return newCol;
}

public object GetEditor(Type editorBaseType)
{
// TODO: Add UserControl1.GetEditor implementation
return null;
}

public PropertyDescriptor GetDefaultProperty()
{
// TODO: Add UserControl1.GetDefaultProperty implementation
return TypeDescriptor.GetDefaultProperty(this,true);
}

public EventDescriptor GetDefaultEvent()
{
// TODO: Add UserControl1.GetDefaultEvent implementation
return TypeDescriptor.GetDefaultEvent(this,true);
}

public string GetClassName()
{
// TODO: Add UserControl1.GetClassName implementation
return TypeDescriptor.GetClassName(this,true);
}

#endregion
}
class DummyPropertyDescriptor : PropertyDescriptor
{
public DummyPropertyDescriptor(string name)
:base(name,null)
{
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get
{
return typeof(Component);
}
}
public override object GetValue(object component)
{
return null;
}
public override void SetValue(object component, object value)
{
}
public override Type PropertyType
{
get
{
return typeof(string);
}
}

public override bool IsReadOnly
{
get
{
return false;
}
}
public override void ResetValue(object component)
{

}

public override bool ShouldSerializeValue(object component)
{
return false;
}
}
}
</code>

Hope it helps!


Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
C

Colin Young

That should do it. Thanks.

Colin

"Ying-Shen Yu[MSFT]" said:
Hi Colin,

Here is a simple sample for adding a dummy property into the
PropertyCollection.
<code>
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace _DesignTime__ICustomTypeDescriptor_
{
/// <summary>
/// Summary description for UserControl1.
/// </summary>
public class UserControl1 :
System.Windows.Forms.UserControl,ICustomTypeDescriptor
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public UserControl1()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();

// TODO: Add any initialization after the InitializeComponent call

}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion

#region ICustomTypeDescriptor Members

public TypeConverter GetConverter()
{
// TODO: Add UserControl1.GetConverter implementation
return null;
//return TypeDescriptor.GetConverter(this);
}

public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
// TODO: Add UserControl1.GetEvents implementation
return TypeDescriptor.GetEvents(this,attributes,true);
}

EventDescriptorCollection
System.ComponentModel.ICustomTypeDescriptor.GetEvents()
{
// TODO: Add
UserControl1.System.ComponentModel.ICustomTypeDescriptor.GetEvents
implementation
return TypeDescriptor.GetEvents(this,null,true);
}

public string GetComponentName()
{
// TODO: Add UserControl1.GetComponentName implementation
return TypeDescriptor.GetComponentName(this,true);
}

public object GetPropertyOwner(PropertyDescriptor pd)
{
// TODO: Add UserControl1.GetPropertyOwner implementation
if (pd == null)
return this;
else return pd.GetValue(GetPropertyOwner(pd));
}

public AttributeCollection GetAttributes()
{
// TODO: Add UserControl1.GetAttributes implementation
//return TypeDescriptor.GetAttributes(this,true);
//need return an empty collectiom
return TypeDescriptor.GetAttributes(this,true);
}

public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
// TODO: Add UserControl1.GetProperties implementation
return ((ICustomTypeDescriptor)this).GetProperties();
}

PropertyDescriptorCollection
System.ComponentModel.ICustomTypeDescriptor.GetProperties()
{
// TODO: Add
UserControl1.System.ComponentModel.ICustomTypeDescriptor.GetProperties
implementation
PropertyDescriptorCollection col =
TypeDescriptor.GetProperties(this,null,true);

ArrayList props = new ArrayList(col);
props.Add(new DummyPropertyDescriptor("Dummy"));
PropertyDescriptorCollection newCol = new PropertyDescriptorCollection(
(PropertyDescriptor[])props.ToArray(typeof(PropertyDescriptor)));

return newCol;
}

public object GetEditor(Type editorBaseType)
{
// TODO: Add UserControl1.GetEditor implementation
return null;
}

public PropertyDescriptor GetDefaultProperty()
{
// TODO: Add UserControl1.GetDefaultProperty implementation
return TypeDescriptor.GetDefaultProperty(this,true);
}

public EventDescriptor GetDefaultEvent()
{
// TODO: Add UserControl1.GetDefaultEvent implementation
return TypeDescriptor.GetDefaultEvent(this,true);
}

public string GetClassName()
{
// TODO: Add UserControl1.GetClassName implementation
return TypeDescriptor.GetClassName(this,true);
}

#endregion
}
class DummyPropertyDescriptor : PropertyDescriptor
{
public DummyPropertyDescriptor(string name)
:base(name,null)
{
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get
{
return typeof(Component);
}
}
public override object GetValue(object component)
{
return null;
}
public override void SetValue(object component, object value)
{
}
public override Type PropertyType
{
get
{
return typeof(string);
}
}

public override bool IsReadOnly
{
get
{
return false;
}
}
public override void ResetValue(object component)
{

}

public override bool ShouldSerializeValue(object component)
{
return false;
}
}
}
</code>

Hope it helps!


Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top