Nested Datalists down to GreatGrandChild level - parent-child

I've been "successful" at getting nested datalists to work through four generations (Parent, Child, GrandChild, GreatGrandChild) but only with recordsets less than 50 and almost a minute of churn time. Now that I've got about 500 records, the request is timing out.
I've tried several methods I've found online for successfully getting Parent-Child datalists but I couldn't get recursing to work through to GrandChild without an error for using too many Open Connections.
Could anyone share a best practice for a speedy, four-generation nested datalist?
Here is the example code behind for databinding the Child and GrandChild datalists:
Sub Item_Bound_Child(sender As Object, e As DataListItemEventArgs)
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
' Retrieve the Label control in the current DataListItem.
Dim Parent_Name_Label As Label = _
CType(e.Item.FindControl("lbl_Parent_Name"), Label)
Dim s As SqlDataSource = DirectCast(e.Item.FindControl("DataSource_Child_Data"), SqlDataSource)
s.FilterParameters(0).DefaultValue = Parent_Name_Label.Text
s.DataBind()
End If
End Sub
Sub Item_Bound_GrandChild(sender As Object, e As DataListItemEventArgs)
If e.Item.ItemType = ListItemType.Item Or _
e.Item.ItemType = ListItemType.AlternatingItem Then
' Retrieve the Label control in the current DataListItem.
Dim Parent_Name_Child_Level_Label As Label = _
CType(e.Item.FindControl("lbl_Parent_Name_Child_Level"), Label)
Dim Child_Name_Label As Label = _
CType(e.Item.FindControl("lbl_Child_Name"), Label)
Dim s As SqlDataSource = DirectCast(e.Item.FindControl("DataSource_GrandChild_Data"), SqlDataSource)
s.FilterParameters(0).DefaultValue = Parent_Name_Child_Level_Label .Text
s.FilterParameters(1).DefaultValue = Child_Name_Label .Text
s.DataBind()
End If
End Sub
I can only imagine that I'm leaking something somewhere or doing too many round-trips. I sure would appreciate some direction and help.
Thanks,
Rob

I found this explanation to be very helpful to set up databinding for multiple-level nested datalists. While the code was initially very intimidating, I learned it and adapted it to my use.
http://msdn.microsoft.com/en-us/library/aa478959.aspx
Now my nested datalists display in a matter of seconds.
My next step is to learn how to edit the GreatGrandChild datalist in place.

Related

Hiding DataGrid column except the header in asp.net using vb

I was able to hide my unwanted column and rows in my DataGrid using OnItemDataBound
e.Item.Cells(0).Visible = False
but the problem is the Headers are also disappearing. How can i hide the rows only and remain its header visible?
You have to check the DataGridItem.ItemType and only apply the code if it's Item or AlternatingItem to skip the Header:
Sub Item_Bound(sender As Object, e As DataGridItemEventArgs)
If e.Item.ItemType = ListItemType.Item OrElse _
e.Item.ItemType = ListItemType.AlternatingItem Then
e.Item.Cells(0).Visible = False
End If
End Sub
As an aside, if you loop all Items in the grid all other ItemTypes are skipped automatically.
For Each item As DataGridItem In dataGrid1.Items
' Here only Item/AlternatingItem items are available, others are omitted by default.
Next

Unable to cast object of type 'System.Web.UI.WebControls.RadioButtonList' to type 'System.Web.UI.WebControls.TableRow'

I have a 4 tier architecture using asp.net 4.0
1- Web application
2- Business object
3- Business Logic
4- Data Logic
i have used factory method to create dynamic forms. on a radio button list selected index changed event , i want to hide/show a table row which is also created dynamically. table row is available in session. i am using the following code
Private Sub parameter_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Try
Dim rdbtn As RadioButtonList = DirectCast(sender, RadioButtonList)
Dim selectedText As String = rdbtn.SelectedItem.Text
Dim worksRequiredRowId = SessionManager.getWorksRequiredRowId()
Dim worksRequiredRow As TableRow = CType(sender.FindControl(worksRequiredRowId), TableRow)
If selectedText.ToUpper <> ApplicationConstants.conditionSatisfactory.ToUpper Then
worksRequiredRow.Style.Add("display", "table-row")
Else
worksRequiredRow.Style.Add("display", "none")
End If
Catch ex As Exception
End Try
End Sub
And i get the following error.
Unable to cast object of type
'System.Web.UI.WebControls.RadioButtonList' to type
'System.Web.UI.WebControls.TableRow'.
Please help me to find out the solution.
Best ragards.
You can actually hide that particular item from radio button list instead of converting it into table row. Something like this.
If rdbtn.SelectedItem.Text <> selectedText.ToUpper <> ApplicationConstants.conditionSatisfactory.ToUpper Then
rdbtn.Items(itemIndex).Attributes.CssStyle.Add("display", "none")
End If
I hope this helps.
I think your mistake is confusing the generated HTML markup with the raw ASP.NET markup. RadioButtonList does create an HTML for each item, but you can't access that rows at the server-side (to make them visible or hidden).
You should either use the server-side method mentioned in Bridewin D.P.'s answer or transfer the code to client-side and use Javascript to manipulate the rows.
Server-side would look something like this:
Private Sub parameter_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Try
Dim rdbtn As RadioButtonList = DirectCast(sender, RadioButtonList)
Dim selectedText As String = rdbtn.SelectedItem.Text
Dim worksRequiredRowId = SessionManager.getWorksRequiredRowId()
Dim style as String
If selectedText.ToUpper <> ApplicationConstants.conditionSatisfactory.ToUpper Then
style= "table-row"
Else
style= "none"
End If
rdbtn.Items(worksRequiredRowId).Attributes.CssStyle.Add("display", style)
Catch ex As Exception
End Try
End Sub

Unable to cast object of type 'System.Data.Entity.DynamicProxies to type 'System.Data.DataRowCollection'

May be my question is simple or i am new to this ,the thing is While trying to do the below code in the item data bound of a repeater im gettin the error Unable to cast object of type
*System.Data.Entity.DynamicProxies.AutoPublishLog_06BC2AA20C3D11E56D78DD544C2C7E5211D828344650C93B9AA23BDEE16A6DCE' to type 'System.Data.DataRowView''.*
Error Line is
Dim row As System.Data.DataRowView = DirectCast(e.Item.DataItem, System.Data.DataRowView)
Any help ,Thanks in advance
code snippet
Protected Sub AutoPublishList_ItemDataBound(ByVal sender As Object, ByVal e As
System.Web.UI.WebControls.RepeaterItemEventArgs) Handles AutoPublishList.ItemDataBound
If e.Item.ItemType = ListItemType.AlternatingItem OrElse e.Item.ItemType = ListItemType.Item Then
Try
Dim row As System.Data.DataRowView = DirectCast(e.Item.DataItem, System.Data.DataRowView)
Dim pageID As Literal = DirectCast(e.Item.FindControl("PageID"), Literal)
If Convert.ToInt32(row("PageID")) = Business.Objects.Constants.A Then
pageID.Text = "Dummy A"
End If
If Convert.ToInt32(row("PageID")) = Business.Objects.Constants.B Then
pageID.Text = "Dummy B"
End If
Catch ex As Exception
AddErrInfo(ex)
ErrHandler(ex)
End Try
End If
End Sub
You are mixing Classic ADO.NET and Entity Framework objects. These are two different worlds and are not automatically interexchangable.
An EF object is a strongly typed object, I suggest that you cast e.Item.DataItem to your EF type instead. From your exception message I suspect that the EF type is named AutoPublishLog.
Try to cast it to this instead:
Dim row AS AutoPublishLog = DirectCast(e.Item.DataItem, AutoPublishLog)
'your code
If row.PageID = Business.Objects.Constants.A then
'your code
This should work (maybe you need some namespace or other name for AutoPublishLog, but it's hard to tell without knowing your model).
I dont know how to VB.Net, but I think your e.Item.DataItem is not convertible to the type you want... which I doubt. Try to review the types.

Why won't FindControl find the button in the footer of my repeater?

I am using an OnItemDataBound event to attempt to activate a disabled button in a repeater. Quite simply, if the event is triggered, I know there are items in the repeater and therefore want to enable the button. Where I am getting stuck is on casting the button in the function so I can enable it. The relevant part of the repeater code is below:
<asp:Repeater ID="RptEnterHours" runat="server" DataSourceID="SQL_EmployeeGetTimesheet" ClientIDMode="Predictable" OnItemDataBound="RptEnterHours_Bound">
'.....Irrelevant code.....
<FooterTemplate>
<asp:Button Enabled="false" ID="SubmitTimesheets" Text="Submit All Timesheets" OnClick="processTimesheetEntry" runat="server" OnClientClick="checkValues();" />
</FooterTemplate>
</asp:Repeater>
This is my code behind:
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
'Exposes the Submit All Timesheets button if timesheets are available.
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim sButton As Button = TryCast(Me.FindControl("SubmitTimesheets"), Button)
sButton.Enabled = True
End If
End Sub
This and all other attempts has yielded the dreaded "Object reference not set to an instance of an object" message. Can anyone tell me what I am doing wrong and why my code behind won't find the button?
please try this i am sure it will help you.
If e.Item.ItemType = ListItemType.Footer Then
Dim btn as new button
btn = CType(e.Item.FindControl("SubmitTimesheets"), Button)
btn.enabled = true
End If
You're restricting it to looking within the item and alternating item templates.
Change this:
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
To:
If (e.Item.ItemType = ListItemType.Footer) Then
You want to test for e.Item.ItemType = ListItemType.Footer. Item and AlternatingItem are used for the actual data records, not the footer. Therefore, the button indeed does not exist for Items and AlternatingItems.
Then, you will want to add a test for whether the RptEnterHours.DataSource object has records. For this, you will need to cast the RptEnterHours.DataSource to whatever type the data source is.
So, basically something like this. You will obviously need to change it to fit your code:
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
'Exposes the Submit All Timesheets button if timesheets are available.
If (e.Item.ItemType = ListItemType.Footer) Then
Dim sButton As Button = TryCast(Me.FindControl("SubmitTimesheets"), Button)
Dim myDataSource = CType(RptEnterHours.DataSource, MyDataSourceType)
sButton.Enabled = (myDataSource.Count > 0)
End If
End Sub
It's been a little while since I've worked with web forms, but I believe the problem is two fold.
When the item type is Item or AlternatingItem then you know you have data in the repeater. In those cases you could set an instance level flag to indicate that you have items.
Then, when the item type is footer AND you have items you want to enable to button. The way to do this is mentioned in an unaccepted answer to the question linked to by #codingkiwi.com, but I believe the problem is the context in which you're calling FindControl. You are calling Me.FindControl which will search the level 1 children of the page (or user control, or control, or whatever Me is a reference to). You want to be searching the child controls of the actual repeater element, which in this case is the footer. So the search becomes e.Item.FindControl.
It should be noted that there are probably more elegant ways to detect whether or not a repeater control has elements. Perhaps all you need to check for in the OnDataBound event is the footer item, and then look for something like: (my VB may be a bit rusty too)
If (Me.RptEnterHours.Items IsNot Null AndAlso Me.RptEnterHours.Items.Any()) Then
Not sure why its just not enabled in the first place, but this will work since it will fire for the footer after the Item/AlternatingItem types:
Private m_bolEnableButton As Boolean = False
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
'Exposes the Submit All Timesheets button if timesheets are available.
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
'"if the event is triggered, I know there are items in the repeater and therefore want to enable the button"
m_bolEnableButton = True
End If
If e.Item.ItemType = ListItemType.Footer Then
If m_bolEnableButton Then
Dim sButton As Button = TryCast(e.Item.FindControl("SubmitTimesheets"), Button)
sButton.Enabled = True
End If
m_bolEnableButton = False
End If
End Sub
The reason you get the Object null reference exception is because you are fixated on the cast, which isn't causing the problem. You can generally safely cast the results of FindControl implicitly. What you need to explicitly check for is a null reference AFTER the FindControl results are captured.
Also, you should be looking for ListItemType.Footer so you can reference the footer row.
Finally, FindControl() is not recursive. It only finds controls within the top-level naming container. In most databound controls, each row represents its own naming container, so you must FindControl within the row you want to search. When you use Me, it refers to the page. You should instead use e.Item.FindControl().
Code:
Dim bRecordsFound as Boolean = False
Sub RptEnterHours_Bound(Sender As Object, e As RepeaterItemEventArgs)
If (e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem) Then
bRecordsFound = True
End If
If (e.Item.ItemType = ListItemType.Footer) And (bRecordsFound) Then
Dim sButton As Button = e.Item.FindControl("SubmitTimesheets")
If sButton IsNot Nothing Then
sButton.Visible = True
End If
End If
End Sub

How can i add a row to a data-bound gridview without causing viewstate errors?

I'm trying to add a row grouping row to my data-bound gridview. It works fine on the first response, but at the postback i got the "Failed to load viewstate" error.
There is the code for the GridView's RowDataBound event:
Private Sub AddGroupingRow(ByRef eRow As GridViewRow, ByVal Css As String, ByVal ColSpan As Integer, ByVal Txt As String)
Dim cell As New TableCell()
cell.ColumnSpan = ColSpan
cell.CssClass = "Spacing FieldCell"
cell.Text = Txt
Dim row As New GridViewRow(-1, -1, DataControlRowType.DataRow, DataControlRowState.Normal)
row.CssClass = Css
row.Cells.Add(cell)
Dim tbl As Table
tbl = eRow.Parent
tbl.Rows.AddAt(eRow.RowIndex + 1, row)
End Sub
Private Prev_Client_ID As Integer = -1
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim dr As Data.DataRowView = TryCast(e.Row.DataItem, Data.DataRowView)
If dr IsNot Nothing AndAlso dr.Row.RowState <> Data.DataRowState.Added Then
Dim Client_ID As Integer = dr.Item("Client_ID")
If Client_ID <> Prev_Client_ID Then AddGroupingRow(e.Row, "Group", 8, dr.Item("Client_Name"))
Prev_Client_ID = Client_ID
End If
End If
End Sub
I know that it's easier to create the grouping rows at the datasource, but deriving from this code, i want to create some base to other grids at the site.
Try this link. it should help you. I too had the same problem. The only way to resolve is a proper understanding of viewstate.
After some thinking, the answer could not be simpler: disable the viewstate of the gridview.
I was re-binding the datasource at every paging or sorting, so the need for the viewstate was minimum, except for the PageSize and PageIndex, that i became forced to keep track manually.
This is a considerable trade-off: things like PageSize and PageIndex must be managed manually afterwards, since their state are keeped by the ViewState.
So, even doing exactly what i was meant to do, i've decided to adopt an simple alternative solution:
If Cliente_ID <> Cliente_ID_Anterior Then
For i As Integer = 0 To e.Row.Cells.Count - 1
e.Row.Cells(i).Style("border-top") = "solid 1px #777777"
Next
e.Row.Cells(0).Style("border-bottom") = "none"
Else
e.Row.Cells(0).Text = " "
e.Row.Cells(0).Style("border-top") = "none"
e.Row.Cells(0).Style("border-bottom") = "none"
End If
It still groups the column, but in another way, and is more sort friendly. I could use rowspans and turn cells invisible, but it would be harder to keep. Besides, I'll need to paint the line when the user moves the mouse over it, and a rowspan would hinder a lot.

Resources