I'm not sure if this is a bug or not, but here is the issue I am experiencing: I am binding a custom collection to a grid but for bands more than two levels deep, no columns will display.
I am using a System.Collections.ObjectModel.Collection(Of T) class. I am using it to store a simple class that looks like:
As you can see, the only interesting thing this class has is a reference to another collection that also contains Issues.
So say I have a form with a grid on it and then populate a collection with some Issue objects. The grid will correctly display the first and second bands, but for the third band, it will show no columns and no rows - although it looks like something should be there (you can see the indicators and spacing where the columns should be).
Here is the code that populates and binds the collection. There are three Issues in the collection: the first one has no children, the second one has one child, and the third one has one child that itself has a child.
This will display the grid but there are no rows or column headers (the columns collection is empty in the band) for the Root3/Child/Child row - although it looks like something is there since it shows the indicator and has the spacing for it.
The thing is that adding the Root3 issue as the first issue in the collection (with its child and the child's child) will work. It seems that the grid is just looking at the first item in the collection to determine 'how far down to go' for band displaying (but the databinding logic sort of works since it at least seems that it 'knows' something is really there).
Does anyone have any ideas on whether this is a bug or if there is a setting I could use to force the grid to determine how many bands to display? I've tried every setting I could think of. Binding to a DataSource or DataSet with a self-referencing table object bound to the grid at design-time and then populating it at run time works, but I would really like to associate the object in the collection with the grid and not have that intermediary (and I'm not quite sure how deep the collection will get - although realistically no more than five levels deep).
Thanks in advance for any pointers.
-David
I'm having the same issue with the UltraWinGrid. I have a collection that represents a multilevel Bill of Materials. Certain child bands appear with empty rows and the row's Cell and Column collections are empty. This causes problems because I'm trying to set row background colors during the InitializeLayout, based on the values in certain columns. This exibits a similar behavior in the UltraTree as well, only it does not show the empty space where the row should be, it just shows up like the nodes have no children. I just updated to 2008 v3 and the same behavior exists. I also checked, but there are no hotfixes under v3 yet.
I did notice however, if you clicked on the parent row and started to edit a cell, the missing child rows suddenly appear. My workaround was to programmatically enter edit mode for the parent rows of each row that was missing its columns.
Below is the code for the my form.
In the SetRowApperance function when I come across a row with missing columns I call the EnterEdit function for the parent row. This seems to have solved my problem.
Private PartNo As String Private Sub frmBomTree_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Text = PartNoDim Bom As M2MInterface.M2M.BOM.BOMItems Bom = M2MInterface.M2M.BOM.PopulateBOMItems(PartNo) grdBom.DataSource = BomgrdBom.BeginInvoke(New MethodInvoker(AddressOf GridInitLayout)) End SubPrivate Sub GridInitLayout() grdBom.Rows.ExpandAll(True) SetRowApperance(grdBom.Rows) EnterEdit(grdBom.Rows(0)) End SubSub EnterEdit(ByVal row As Infragistics.Win.UltraWinGrid.UltraGridRow) If row Is Nothing Then Return grdBom.Focus() grdBom.ActiveCell = row.Cells(0)grdBom.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.ToggleCellSel, False, False) grdBom.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.EnterEditMode, False, False) End SubPublic Sub New(ByVal PartNumber As String) ' This call is required by the Windows Form Designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. PartNo = PartNumberEnd Sub Private Sub SetRowApperance(ByVal rows As Infragistics.Win.UltraWinGrid.RowsCollection) For Each row As Infragistics.Win.UltraWinGrid.UltraGridRow In rows If row.Cells.IndexOf("Source") = -1 Then EnterEdit(row.ParentRow) End If If row.Cells.IndexOf("Source") <> -1 Then Dim source As String = row.Cells("Source").Value If source = "M" Then row.Appearance.BackColor = Color.Pink row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True ElseIf source = "S" Then row.Appearance.BackColor = Color.Beige ElseIf source = "B" Then row.Appearance.BackColor = Color.LightGreen ElseIf source = "P" Then row.Appearance.BackColor = Color.LightBlue row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True End If End If If Not row.ChildBands Is Nothing Then For Each band As Infragistics.Win.UltraWinGrid.UltraGridChildBand In row.ChildBands SetRowApperance(band.Rows) NextEnd If NextEnd Sub
Private PartNo As String
Me.Text = PartNoDim Bom As M2MInterface.M2M.BOM.BOMItems Bom = M2MInterface.M2M.BOM.PopulateBOMItems(PartNo) grdBom.DataSource = BomgrdBom.BeginInvoke(New MethodInvoker(AddressOf GridInitLayout))
Me.Text = PartNo
Bom = M2MInterface.M2M.BOM.PopulateBOMItems(PartNo)
grdBom.DataSource = Bom
End Sub
grdBom.Rows.ExpandAll(True) SetRowApperance(grdBom.Rows) EnterEdit(grdBom.Rows(0))
SetRowApperance(grdBom.Rows)
EnterEdit(grdBom.Rows(0))
If row Is Nothing Then Return grdBom.Focus() grdBom.ActiveCell = row.Cells(0)grdBom.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.ToggleCellSel, False, False) grdBom.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.EnterEditMode, False, False)
If row Is Nothing Then Return
grdBom.Focus()
grdBom.ActiveCell = row.Cells(0)
grdBom.PerformAction(Infragistics.Win.UltraWinGrid.UltraGridAction.EnterEditMode, False, False)
' This call is required by the Windows Form Designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. PartNo = PartNumber
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
PartNo = PartNumber
For Each row As Infragistics.Win.UltraWinGrid.UltraGridRow In rows If row.Cells.IndexOf("Source") = -1 Then EnterEdit(row.ParentRow) End If
If row.Cells.IndexOf("Source") = -1 Then EnterEdit(row.ParentRow)
If row.Cells.IndexOf("Source") = -1 Then
EnterEdit(row.ParentRow)
End If
If row.Cells.IndexOf("Source") <> -1 Then Dim source As String = row.Cells("Source").Value If source = "M" Then row.Appearance.BackColor = Color.Pink row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True ElseIf source = "S" Then row.Appearance.BackColor = Color.Beige ElseIf source = "B" Then row.Appearance.BackColor = Color.LightGreen ElseIf source = "P" Then row.Appearance.BackColor = Color.LightBlue row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True End If End If If Not row.ChildBands Is Nothing Then For Each band As Infragistics.Win.UltraWinGrid.UltraGridChildBand In row.ChildBands SetRowApperance(band.Rows) NextEnd If Next
If row.Cells.IndexOf("Source") <> -1 Then Dim source As String = row.Cells("Source").Value If source = "M" Then row.Appearance.BackColor = Color.Pink row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True ElseIf source = "S" Then row.Appearance.BackColor = Color.Beige ElseIf source = "B" Then row.Appearance.BackColor = Color.LightGreen ElseIf source = "P" Then row.Appearance.BackColor = Color.LightBlue row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True End If End If If Not row.ChildBands Is Nothing Then For Each band As Infragistics.Win.UltraWinGrid.UltraGridChildBand In row.ChildBands SetRowApperance(band.Rows) NextEnd If
If row.Cells.IndexOf("Source") <> -1 Then
Dim source As String = row.Cells("Source").Value
If source = "M" Then row.Appearance.BackColor = Color.Pink row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True ElseIf source = "S" Then row.Appearance.BackColor = Color.Beige ElseIf source = "B" Then row.Appearance.BackColor = Color.LightGreen ElseIf source = "P" Then row.Appearance.BackColor = Color.LightBlue row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True End If
If source = "M" Then
row.Appearance.BackColor = Color.Pink row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True
row.Appearance.BackColor = Color.Pink
row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True
ElseIf source = "S" Then
row.Appearance.BackColor = Color.Beige
ElseIf source = "B" Then
row.Appearance.BackColor = Color.LightGreen
ElseIf source = "P" Then
row.Appearance.BackColor = Color.LightBlue row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True
row.Appearance.BackColor = Color.LightBlue
If Not row.ChildBands Is Nothing Then
For Each band As Infragistics.Win.UltraWinGrid.UltraGridChildBand In row.ChildBands SetRowApperance(band.Rows) Next
SetRowApperance(band.Rows)
Next
End Class
dpalau said:I turned off the property to auto-generate the column sets and have defined my own (set in the Override.ColumnSet property) but when I attach my collection to the treeview datasource, I now get no child nodes what so ever.. I can get around that I guess by manually adding nodes with some column information and then attaching the actual issue object to the node.Tag property, but I sure wish there was some way to set the datasource and just have done with it.
When defining your own column sets, you have to remember that a child band is actually a column. My guess is that you are not getting any child nodes because you didn't add the child band column to the ColumnSet. You need to add a column to the ColumnSet with the same key as the child band and set IsChaptered on the column to true to indicate that it should display as a child band instead of as a cell.
Another funny incident I found with using the grid with my custom collection is that I can get the 'missing' child rows to appear if I select and make the ActiveRow the parent row. Now the InitializeLayout or InitializeRow events don't fire so I don't see the columns formatted correctly, but the data at least 'appears'.
I wonder if somehow I can trigger some sort of action to show those rows and re-run the layout initialization code?
Something also strange is that if use my example above with the missing rows, after the InitializeLayout even, I will have 3 bands and the Columns.Count of the last band will be 0. But after I do the trick of selecting the parent row, there will now be 5 bands in the DisplayLayout and all but the last one will have the correct column count in it (the last band will still have 0 columns but everything seems to display).
I'm currently using the latest 2008 Vol 2. edition.
I turned off the property to auto-generate the column sets and have defined my own (set in the Override.ColumnSet property) but when I attach my collection to the treeview datasource, I now get no child nodes what so ever.. I can get around that I guess by manually adding nodes with some column information and then attaching the actual issue object to the node.Tag property, but I sure wish there was some way to set the datasource and just have done with it.
Like I mentioned before, for the grid, I don't understand why it will correctly populate Band #2 for a subsequent item when the first item in the collection doesn't have any child issues but it won't do Band #3 or later. I would think that if Band #2 would have 'blank' rows as well. There must be some logic in there that makes it go down at least one band level.
Thanks for your help.
Okay, then the first thing I recommend is that you get the latest Hot Fix. There was an issue a while back where some of the data binding code was stopping after 3 levels in some case, so maybe you are running into that.
If the tree still doesn't work, then it's most likely because you are letting the tree auto-generate the column sets and it's running into the same problem the grid has. The difference is that the tree will be able to access the data on different parent nodes, so you might have to manually set up your column sets to prevent the tree from using the wrong one.
dpalau said:Maybe I'll try the ITypedList interface. Did you mean I have to try both strategies (ITypedList and IEditableObject) to potentially get it to work or would just one or the other be sufficent?
Theoretically, ITypedList should give the binding manager enough information to determine the data structure. In my experience, though, I haven't had much luck with this and I suspect the BindingManager might not be smart enough to look for it. So I would try IEditableObject first.