Overloaded inherited treenode

VisuallyImpared
01-18-2007, 05:58 AM
Hey folks,

I am creating my own tree nodes with some special properties. One of which is a node image(icon) that has some javascript elements added to the htmlattributes.

This works fine on the initial load but the node images dissapear after a post back.

Here is how the nodes are being generated (the application is loading a bill of materials)

1) The user selects a component
2) The application goes to the database and retrieves all the sub-components and returns them in a dataset.

3) Each row of the dataset is stepped through and a node is added to the tree. The icon for each node is dependant on the part type data for that part (a mechanical part gets a screw icon, an electrical part gets a PCB icon, etc.)
4) The javascript added to the icon htmlattributes adds an 'onmouseover' routine to the icon. so when the user hvers over the part icon the part# BOM quantity, Description, etc appear in a floating window over teh mouse.

5) If the user clicks on a subassembly with sub assemblies of its own the application does the same thing as it did before (gets a dataset and adds nodes) this time the nodes are added to the selected node.

This goes on and on down the assemblies untill there are no more sub assemblies. As I said it work perfectly BUT there is one problem:

Only the newest level of the BOM contains the Icons with the JavaScript Tags. As soon as there is a postback the nodes lose their icons and the attached htmlattributes.

Anyone have any idea how to make these custom nodes survive a postback?

Here is my overloaded treenode:

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols


Public Class ExtendedTreeview
Inherits TreeNode


Private M_Lib As ListDictionary
Private _Ico As Image


Public Property Part_Ico() As Image
Get
Return _Ico
End Get
Set(ByVal value As Image)
_Ico = value
End Set
End Property

Public Property Status_Icon() As ListDictionary
Get
Return M_Lib
End Get
Set(ByVal value As ListDictionary)
M_Lib = value
End Set
End Property

Protected Overrides Sub RenderPretext(ByVal writer As HtmlTextWriter)
Dim DE As DictionaryEntry
Dim PN As String
Dim Desc As String
If Not M_Lib Is Nothing Then

PN = M_Lib("PartNo")
Desc = M_Lib("Desc")
End If

With _Ico
writer.AddAttribute("src", _Ico.ImageUrl.ToString.Substring(2))
writer.AddAttribute("onmouseover", "return overlib('<b>Part Number:</b> " & _
PN & "<br><b>Description:</b> " & Desc & "', CSSCLASS)")
writer.AddAttribute("onmouseout", "return nd()")


writer.RenderBeginTag(HtmlTextWriterTag.Img)
writer.RenderEndTag()
End With


End Sub
End Class


And here is how I create the node:



Protected Sub treeBOM_SelectedNodeChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles treeBOM.SelectedNodeChanged
Dim ObjParts As New VisualPartsService 'my webservice that gets parts info for me
Dim ReturnedValues As New DataSet
Dim PN As String = treeBOM.SelectedNode.Value.Split("|")(0)
Dim REV As String = treeBOM.SelectedNode.Value.Split("|")(1)

ReturnedValues = ObjParts.GetAssemblyParts(PN, REV)

If ReturnedValues.Tables.Count > 0 Then
If ReturnedValues.Tables(0).Rows.Count > 0 Then
Dim DR As DataRow
For Each DR In ReturnedValues.Tables(0).Rows
Dim objPart As New VisualPartsService
Dim MyPart As New PartDetails
MyPart = objPart.GetPartDetails(DR("PartNumber"))
Dim NewNode As New ExtendedTreeView
NewNode.Text = "PN: " & DR("PartNumber") & " Rev: " & DR("Revision")
NewNode.Value = DR("PartNumber") & "|" & DR("Revision")
Dim im As New Image
im.ImageUrl = GetNodeImage(DR("B2PARTTYPE"))
Dim SI As New ListDictionary
SI.Add("PartNo", MyPart.PartNumber)
SI.Add("Desc", MyPart.Description)
NewNode.Status_Icon = SI
NewNode.Part_Ico = im

treeBOM.SelectedNode.ChildNodes.Add(NewNode)

Next
End If

End If
treeBOM.SelectedNode.Expand()
End Sub

wayneph
01-18-2007, 08:30 AM
I'm not sure why you're overriding the RenderPreText Method. (For example the ImageURL property should be written automatically, you shouldn't have to write the src attribute.) If you just build the Image object can't you just insert it into the Control Array of the containing node? Then the ASP.NET engine should render everything appropriately.

Or am I missing something?

VisuallyImpared
01-18-2007, 08:46 AM
I don't think you are missing anything, I on the other hand most likely am.

OK, I am trying to wrap my head around what you are getting at here (but I just finished understanding what I had written)

If it were just the image it would be straight forward but with the addition of the onmouseover and onmouse out tags on the control, how else could I render the tags?

wayneph
01-18-2007, 08:58 AM
This will allow you to add the attributes to your object.

_Ico.Attributes.Add("onmouseout","return nd()")

Then you just need to make sure it's in the Control Array. I haven't worked a lot with the the TreeViews, so I'm not familiar with their exact layout. But with in the Current Node, there should be a Control Collection. Since your class Inherits from TreeNode, you probably just need to use the "Me" object.

Me.Controls.AddAt(0,_Ico)

VisuallyImpared
01-18-2007, 09:17 AM
This is why the override (why do I have overloaded?) anyway, the override is because the node object has no controls. You have to add the html. Or at least that is the onlyway I have found to handle this type of situation.

I am starting to uderstand my situation a little better just by explaining it to someone else.

The Image is not included as a control in the tree node so I can't just add the image. To get arround this I am overridding the IMG tag before the node and adding in the details from the Image I created. I didn't really need to use an image any kind of array would have worked here as I have to read out the image settings to the newly created IMG tag I am adding with the html writer.

But my original problem still exists.... How to make it survive a postback

VisuallyImpared
01-18-2007, 12:02 PM
I have modified the code somewhat and am attempting to use the load and save state methods to survive postbacks.

My code for the overridden node now looks like this :

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols


Public Class ExtendedTreeview
Inherits TreeNode

Private _IcoPath As String
Private _MouseOver As String
Private _MouseOff As String

Public Property IcoPath() As String
Get
Return _IcoPath
End Get
Set(ByVal value As String)
_IcoPath = value
End Set
End Property

Public Property MouseOver() As String
Get
Return _MouseOver
End Get
Set(ByVal value As String)
_MouseOver = value
End Set
End Property

Public Property MouseOff() As String
Get
Return _MouseOff
End Get
Set(ByVal value As String)
_MouseOff = value
End Set
End Property

Protected Overrides Sub RenderPretext(ByVal writer As HtmlTextWriter)

Dim MouseOver As String = _MouseOver
Dim MouseOut As String = _MouseOff
writer.AddAttribute("src", _IcoPath)
writer.AddAttribute("onmouseover", MouseOver)
writer.AddAttribute("onmouseout", MouseOut)
writer.RenderBeginTag(HtmlTextWriterTag.Img)
writer.RenderEndTag()

End Sub


Protected Overrides Function SaveViewState() As Object

Dim arrState(5) As Object
arrState(0) = MyBase.SaveViewState
arrState(1) = Me.Text
arrState(2) = Me.MouseOver
arrState(3) = Me.MouseOff
arrState(4) = Me.IcoPath

Return arrState

End Function

Protected Overrides Sub LoadViewState(ByVal state As Object)

If Not state Is Nothing Then
Dim arrState() As Object = state

Me.Text = arrState(1)
Me.MouseOver = arrState(2)
Me.MouseOff = arrState(3)
Me.IcoPath = arrState(4)
MyBase.LoadViewState(arrState(0))

End If
End Sub

End Class

This Woks well on the firs tier of the tree. all the js stuff is passed directly into MouseOver and MouseOff, the path for the icon as well.

Which works OK for the initial load of values into the base nodes, but as soon as I click on one of the bac=se nodes to go down another lever (keep in mind I add the nodes on the fly) i get the following error:

Server Error in '/VisualPartsTool' Application.
--------------------------------------------------------------------------------

Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


[HttpException (0x80004005): Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.]
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +483
System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +195
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +424
System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +195
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +424
System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +195
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +424
System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +195
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +424
System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +195
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +424
System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +195
System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +424
System.Web.UI.Page.LoadAllState() +559
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2238

wayneph
01-18-2007, 05:25 PM
By adding controls dynamically, do you mean in JavaScript? Or during a PostBack procedure?

It sounds like you're doing it in JavaScript, and it would lead to the exact problem you're describing. I think you're going to need to post back, and add new items on the server. Are you using .NET 1.1 or 2.0? If 2.0, I'd suggest taking a look at the Ajax.NET framework (http://ajax.asp.net). That will let you post back just a portion of the page.

VisuallyImpared
01-18-2007, 10:01 PM
Actually what is happening is this:

I have treeNode inherited control called ExtendedTreeView

I override the renderpretext tags and add in the mouse over and mouseout events for an image and assign the image a source.

In my application, when the nodes are being created I create a new ExtendedTreeView and give it the Mouseover, mouseout and imagesource properties.

The remainder of the treenode is the same. The click event for the node fires the same way it had before I had overridden the base.

There is no Java Script creation of nodes or other objects here. THe overridden nodes make use of the HTMLWriter on the server side to add in the extra kinky bits I wanted.

I am currently able to get the thing to work up to the first post back and am trying to explicitly save the controls' state, but I get the error listed in my last post when it runs now.

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum