Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm Controls / December 2006

Tip: Looking for answers? Try searching our database.

DataGridView bound to complex object?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Bradley Plett - 30 Nov 2006 21:33 GMT
I have a class as follows (this is over-simplified, but
representative):
class cMessage
{
 Guid UniqueID;
 string Subject;
 cActor Sender;
 cActor Receiver;
}

Using a "List" (I love generics!) of this class type works fine as the
datasource for a DataGridView.  However, as you'll notice, the sender
and receiver are themselves instances of:
class cActor
{
 Guid UniqueID;
 string FirstName;
 string LastName;
}
I would like to display Sender.FirstName and Sender.LastName as
columns in the grid.  Simply setting the "DataPropertyName" to, for
example, Sender.FirstName compiles, but doesn't show the data.  I
would think this should be simple, but I have not yet succeeded in
doing so.  Any ideas?

Thanks!
Brad.
Linda Liu [MSFT] - 01 Dec 2006 13:11 GMT
Hi Brad,

Thank you for posting here.

This is a quick note to let you know that I am researching on this issue
and will get it back to you ASAP.

I appreciate your patience.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Bradley Plett - 05 Dec 2006 07:22 GMT
Any luck?

Brad.

>Hi Brad,
>
[quoted text clipped - 28 lines]
>
>This posting is provided "AS IS" with no warranties, and confers no rights.
Linda Liu [MSFT] - 05 Dec 2006 12:23 GMT
Hi Brad,

Sorry for my delayed reply. I have spent much time researching on this
problem, but unfortunately with no luck.

When a DataGridView control is bound to a data source, e.g. a list which
contains business objects, DataGridView can only find the first level
public properties in the business class. If we bind a column of the
DataGridView to a sub property of a property (if this property has its own
properties) in the business class, DataGridView couldn't find a public
property in the business class with such a name and will return empty
strings for the column.

To achieve the ability of binding a column of a DataGridView to a sub
property of a property in the business class, I think we have to 'add some
extra properties' in the business class, e.g. add properties named
'Sender_FirstName', 'Sender_LastName, etc. in the cMessage class in your
scenario.

I thought a possible way to do this is to implement a custom type
descriptor for the cMessage class. The TypeDescriptor architecture is built
on the core reflection engine and adds additional rules and features.  It
enhances the capabilities of .NET reflection, for example, it enables an
object's metadata to be modified. Thus, we could modify the properties of
the cMessage class using TypeDescriptor.

For more information about TypeDescriptor, TypeDescriptionProvider and
CustomTypeDescriptor, you may visit the following links.

"Type Descriptor Overview"
http://msdn2.microsoft.com/en-us/library/ms171819.aspx

"TypeDescriptor Class  "
http://msdn2.microsoft.com/en-us/library/system.componentmodel.typedescripto
r.aspx

"TypeDescriptionProvider Class"
http://msdn2.microsoft.com/en-us/library/system.componentmodel.typedescripti
onprovider.aspx

"CustomTypeDescriptor Class"
http://msdn2.microsoft.com/en-us/library/system.componentmodel.customtypedes
criptor.aspx

You may also visit the following links to get samples of using
CustomTypeDescriptor.

".NET Matters  ICustomTypeDescriptor, Part 1"
http://msdn.microsoft.com/msdnmag/issues/05/04/NETMatters/default.aspx

".NET Matters  ICustomTypeDescriptor, Part 2"
http://msdn.microsoft.com/msdnmag/issues/05/05/NETMatters/default.aspx

I have performed a test only to find that DataGridView doesn't reply on the
custom type descriptor to get properties.

To following is the main code in my test project.

public class MyCustomTypeDescriptor : CustomTypeDescriptor
   {      
     
       public MyCustomTypeDescriptor(ICustomTypeDescriptor parent)
           : base(parent)
       {  }

       public override PropertyDescriptorCollection GetProperties()
       {            
           PropertyDescriptorCollection cols = base.GetProperties();      
 
           
           PropertyDescriptor[] array = new PropertyDescriptor[cols.Count
+ 1];
           cols.CopyTo(array, 0);
           // add a new PropertyDecriptor to the collection
           // array[cols.Count] = newprop;
         
           PropertyDescriptorCollection newcols = new
PropertyDescriptorCollection(array);            
           return newcols;
       }          
   }

   public class MyTypeDescriptionProvider : TypeDescriptionProvider
   {
       private ICustomTypeDescriptor td;
       public MyTypeDescriptionProvider()
          : this(TypeDescriptor.GetProvider(typeof(cMessage)))
       { }
       public MyTypeDescriptionProvider(TypeDescriptionProvider parent)
           : base(parent)
       { }
       public override ICustomTypeDescriptor GetTypeDescriptor(Type
objectType, object instance)
       {
           if (td == null)
           {
               td = base.GetTypeDescriptor(objectType, instance);
               td = new MyCustomTypeDescriptor(td);
           }
           return td;
       }        
   }

[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
class cMessage
  {
       private int uniqueID;
       private string subject;
       private cActor sender;
       private cActor receiver;

       public int UniqueID
       {
           get { return uniqueID; }
           set { uniqueID = value; }
       }
       public string Subject
       {
           get { return subject; }
           set { subject = value; }
       }        
       public cActor Sender
       {
           get { return sender; }
           set { sender = value; }
       }        
       public cActor Receiver
       {
           get { return receiver; }
           set { receiver = value; }
       }      
   }

   class cActor
   {
       private int uniqueID;
       private string firstName;
       private string lastName;

       public int UniqueID
       {
           get { return uniqueID; }
           set { uniqueID = value; }
       }
       public string FirstName
       {
           get { return firstName; }
           set { firstName = value; }
       }
       public string LastName
       {
           get { return lastName; }
           set { lastName = value; }
       }      
   }

Unfortunately, when the program is run and the DataGridView is populated
with data from the list, the GetProperties method in the
MyCustomTypeDescriptor class is not called at all. So this solution is not
fit for data binding in DataGridView.

Alternatively, you may add some public readonly properties such as
'Sender_FirstName', 'Sender_LastName' and etc. to the cMessage class to
ensure DataGridView could find them. The following is a sample.
class cMessage
{
 .....
    public string Sender_FirstName
    {
        get {return sender.FirstName;}
     }
    .....
}

Hope this helps.
If you have any concerns, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
Bradley Plett - 07 Dec 2006 19:14 GMT
Being relatively new to the DataGridView, I'm wondering:  is it
possible to add a column that will evaluate a function on the data in
the row?  If so, how?

What I had in mind is something like "=GetFirstName([Sender])", where
"GetFirstName" simply returned "Sender.FirstName".

Thanks!
Brad.

>Hi Brad,
>
[quoted text clipped - 176 lines]
>Linda Liu
>Microsoft Online Community Support
Linda Liu [MSFT] - 08 Dec 2006 08:32 GMT
Hi Brad,

I am sorry to say that it's impossible to make a column in a DataGridView
evaluate a function on the data.

When we bind a DataGridView control to a data source, we could only set the
DataPropertyName property of the columns in the data grid view to the
public properties on the data.

I still suggest that you add readonly pubilc properties for the sub
properties of Sender and Receiver properties in the cMessage class, instead
of functions. After you do this, set the DataPropertyName property of the
columns in the data grid view to the readonly pubilc properties.

Hope this helps.
If you have any concerns, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
Bradley Plett - 08 Dec 2006 16:43 GMT
That's actually what I've done, but it introduces another problem in
my case.  The object in question comes from a web service.  In order
to introduce these new read-only properties, I need to inherit from
the class as provided by the WSDL.  However, when I do, then I can't
easily cast from the old object to the new one (or perhaps I just
don't know how).

Brad.

>Hi Brad,
>
[quoted text clipped - 16 lines]
>Linda Liu
>Microsoft Online Community Support
Bradley Plett - 08 Dec 2006 16:46 GMT
P.S.  As I learn more about it, I can't help but be a little surprised
at the lack of functionality of the DataGridView.  Not being able to
map a column to a function seems very restricting to me.

Brad.

>That's actually what I've done, but it introduces another problem in
>my case.  The object in question comes from a web service.  In order
[quoted text clipped - 25 lines]
>>Linda Liu
>>Microsoft Online Community Support
Linda Liu [MSFT] - 11 Dec 2006 09:04 GMT
Hi Brad,

Thank you for your reply.

I understand your feelings. Unfortunately, DataGridView doesn't support
binding to a function at present.

Since the cMessage objects come from a web service, it is not convenient to
either modify the cMessage class or derive from this class.

In fact, we have another way to display the sub properties of the Sender
and Receiver properties in the cMessage object. That is to paint the values
of the sub properties into the DataGridView cells by ourselves. To do this,
handle the CellPainting event of the DataGridView. In order to update the
underlying data source when the values in the cells are update, we could
handle the CellValidated event of the DataGridView to do it.

The following is a sample.

public Form1()
{
     this.dataGridView1.CellPainting += new
DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting);
     this.dataGridView1.CellValidated += new
DataGridViewCellEventHandler(dataGridView1_CellValidated);
}

void dataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e)
{
           if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
           {
               cMessage obj =
this.dataGridView1.Rows[e.RowIndex].DataBoundItem as cMessage;
               if (obj != null)
               {
                  // update the underlying data
                   if (this.dataGridView1.Columns[e.ColumnIndex].Name ==
"Column3")
                   {
                       obj.Sender.FirstName
=this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()
;                  
                   }
                   else if (this.dataGridView1.Columns[e.ColumnIndex].Name
== "Column4")
                   {
                       
obj.Sender.LastName=this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]
.Value.ToString();
                   }
               }
           }
}

void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
           if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
           {  
               cMessage obj =
this.dataGridView1.Rows[e.RowIndex].DataBoundItem as cMessage;
               if (obj != null)
               {
                   // show the value of Sender.FirstName property in the
Column3
                   if (this.dataGridView1.Columns[e.ColumnIndex].Name ==
"Column3")
                   {
                       
this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value =
obj.Sender.FirstName;
                   }
                   // show the value of Sender.LastName property in the
Column4
                   else if (this.dataGridView1.Columns[e.ColumnIndex].Name
== "Column4")
                   {
                       
this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value =
obj.Sender.LastName;
                   }
               }
           }
}

Hope this helps.
If you have anything unclear, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
Linda Liu [MSFT] - 14 Dec 2006 02:51 GMT
Hi Brad,

How about the problem now?

If the problem is not resolved or you have anything unclear, please feel
free to let me know.

Thank you for using our MSDN Managed Newsgroup Support Service!

Sincerely,
Linda Liu
Microsoft Online Community Support

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.