I have Animal class and derived Cat class
: Class Animal
{
Public String Name{ get; set;}
}
Class Cat : Animal
Public string FurColor {get; set;}
Now I have ItemCollection<Animal> animals = new ItemCollection<Animal>(); with a few animal objects. Then I call UltraGrid1.DataSource = animals. The grid correctly shows the columns for the Animal properties.
If I populated the animal collection with a few cat objects. The grid only shows the properties of animal. No cat properties are shown as column of UltraGrid.
If I declare ItemCollection<Cat> cats and set grid data source as cats. The cat properties will be shown in the UltraGrid columns.
In WCF DataContractSerializer I can declare Cat as KnowType of Animal to get collection of anima l correctly recognized as cat. I s there a similar way for the UltraGrid to show the actual data type properties instead of only the base type.
No, I don't believe the WinGrid can support this. There are two problems with this:
I could be wrong about #2, though. And if so, you might be able to acheive what you want by using the WinTree instead of the WinGrid. The WinTree has a ViewStyle called FreeForm, in which you can display non-homogeneous data. But I think you would have to generate the ColumnSets for each possible type and assign them to the nodes yourself - probably in the InitializeDataNode event.
Hi Mike,
The user control is designed to be generic to all animals. So I declare the collection as ItemCollection<animal> _animal. But each time only one type of anumal. therefore data is homogeneous. I populated the _animal with cat objects. In debug I checked the ultraGrid DataSource, it has the right data. The grid should be smart enough to display the derived properties as its columns. There must be a way to do this.
Julie
Hi Julie,
As I said, there's no way to do this. The grid cannot show non-homogenous data. All of the rows in the band must have the same columns. So if your Cat class derives from Animal and has extra properties you want to show just for those row, it will not work.
Hi Mike
My data is homogenous. In the run time the collection will be all cats, or all dogs, or all some other animal. I design the grid to be generic to all animals; there is no need for the grid to know the data type at the compile time. That is all the beauty of polymorphism.
When I debug the test program I can see that the grid data source did have information of cat’s properties, only that it did not show the information in columns. It seemed to me that column structure is defined by the type of the declaration of data source, in this case ItemCollection<Animal>, instead of the actual data assigned to data source. I tried to add columns for the cat’s property in the grid initialize event. The results are the columns I added in are shown in the grid but no data displayed.
I also try design a DataTable with the cat’s properties. Then assign the table to a DataSet, next assign the data set to the grid data source. In this way I had the column schema right but how do I bind the actual data to the data source?
I believe there is a way to do it since Infragistics grid is such a rich and sophisticated grid.
Hi Julie.
zhililin said:My data is homogenous. In the run time the collection will be all cats, or all dogs, or all some other animal. I design the grid to be generic to all animals; there is no need for the grid to know the data type at the compile time. That is all the beauty of polymorphism.
Okay... that makes things easier and it was not clear to me from your previous posts. But even so, it's still not going to work the way you want and it has nothing to do with the grid. If you bind the grid to a BindingList<Animal>, then the DotNet BindingManager is only going to see and expose fields on the Animal type. It doesn't matter what type the items in the list are. Even if they all happen to be the same derived type, the BindingManager cannot assume that that is the case or that it will always be the case.
zhililin said:When I debug the test program I can see that the grid data source did have information of cat’s properties, only that it did not show the information in columns. It seemed to me that column structure is defined by the type of the declaration of data source, in this case ItemCollection<Animal>, instead of the actual data assigned to data source. I tried to add columns for the cat’s property in the grid initialize event. The results are the columns I added in are shown in the grid but no data displayed.
I'm not sure what you mean by this. Where exactly do you see that the grid has information on cat's properties? The data source will have this information, of course. But the BindingManager in DotNet will not (and cannot) expose it, so the grid will know nothing about it.
zhililin said: I also try design a DataTable with the cat’s properties. Then assign the table to a DataSet, next assign the data set to the grid data source. In this way I had the column schema right but how do I bind the actual data to the data source? I believe there is a way to do it since Infragistics grid is such a rich and sophisticated grid.
I don't see any way to do this with a DataSet, unless you simply populate the DataTable with a copy of all the data in your BindingList.
But... as long as you know that all of the items in the list are of the same type, you do have a couple of options.
One option would be to add some unbound columns to the grid to fill in the gaps. That is - you would use the InitializeLayout event of the grid and add an Unbound column for each property that exists on Cat, but not on Animal. Then you would use the InitializeRow event to populate the unbound column with the data from the ListObject of the grid row. ListObject returns the underlying object in the data source, which in this case would be a Cat.
If the fields need to be updatable, then you would have to reverse this process. So you could use BeforeRowUpdate to copy the values from the unbound columns into the Cat object for the row.
The second option would be to use the UltraDataSource in virtual mode as a sort've intermediary between the grid and the "real" data source (the BindingList). You would set up the UltraDataSource with all of the columns you need in the grid and then handle events on the UltraDataSource to give it data as needed. There's a sample of this called the Virtual Mode sample included in both the grid and UltraDataSource samples in the NetAdvantage SDK.
Here is my affert
Looks like the BindingManager in .net only know the declared type instead of the actual type. Anyway I tried both of your options options.
Second option: use the virtual mode.
In the form load event I setup the columns like this:
this.ultraDataSource1.Band.Columns.Add("CatFur", typeof(string));
In the event ultraDataSource1_CellDataRequested I set the cell value using my cat’s collection. I was able to use the property info to set the cat’s data without knowing the derived type Cat. The ulta grid displayed the right info.
Then I make the changes to the data, both base class property and derived property, after making the changes I checked the my cat’s collection, the cat’s collection property values are not changed as I expected. That means my data is not binded with the grid cells..
I tried the first option add a Unbound column:
In the load event I set data source to my Cat’s collection, (which is declared as ItemCollection<Animal>, therefore no derived properties are bind to the grid column). In the initialize event I add a cat’s property column to the ban 0 (I don’t know what you mean Unbound column).
In the InitializeRow event I get the ListObject. But I still have to cast the ListObject to Cat type before I can access the cat property. Event I can cast I cant not get colum info from InitializeRowEventArg. How do I populate the Unbound column data?
The whole design of my user control is no need to know the derived types at the compile time and able to bind the data to the ultra grid data source at the run time with the derived data collection. More suggestions?
zhililin said:Then I make the changes to the data, both base class property and derived property, after making the changes I checked the my cat’s collection, the cat’s collection property values are not changed as I expected. That means my data is not binded with the grid cells..
I'm not sure what this means. If you are making changes to the data and the data in the collection is not changed, then something is wrong with how you are changing it. That has nothing to do with the grid.
If you make changes directly to the data and the grid is not displaying those changes, then the data source is not notifying the grid of the change. This notification comes from the implementation of IBindingList, so if your data source implements this interface and it's still not working, then something is wrong with the implementation. If you data source does not implement IBindingList, then you either need to implement it, or else you will need to refresh the grid data by calling grid.Rows.Refresh(ReloadData) any time something in the data source changes.
zhililin said:In the load event I set data source to my Cat’s collection, (which is declared as ItemCollection<Animal>, therefore no derived properties are bind to the grid column). In the initialize event I add a cat’s property column to the ban 0 (I don’t know what you mean Unbound column).
To add an unbound column, you use the band.Columns.Add method.
zhililin said:In the InitializeRow event I get the ListObject. But I still have to cast the ListObject to Cat type before I can access the cat property. Event I can cast I cant not get colum info from InitializeRowEventArg. How do I populate the Unbound column data?
Yes, you will have to cast the ListObject to the appropriate type. There's no way around that.
To populate the unbound column, you simply set the Value on the cell. Something like this:
e.Row.Cells["CatFur"].Value = ((Cat)e.Row.ListObject).CatFur
Hi,
I'm not sure I follow you.
The grid gets the data from the BindingManager in DotNet. The grid's DataSource needs to support IBindingList or IList in order to function at all - although IBindingList is much more robust. Using an IList will provide limited functionality in the grid.
Anyway, If it works when you use ToList, then my guess is that whatever data source you were using before (without ToList) did not implement the proper interfaces such that the BindingManager in DotNet could get the data structure.
I have the same problem, and actually, this works if you cast your list to a list of objects (using linq: catsThatAreAnimals.Cast<object>().ToList()) before you bind it. I can't see why and it bugs me big time. The declared type is object but still columns are bound to properties of the actual type you provide. Now this could be a list of different types of objects (havnt tried that though). How come this works?