 |
| ASP.NET 1.1 As of 10/6/2005, this forum is locked as part of the reorganization described here: http://p2p.wrox.com/topic.asp?TOPIC_ID=35394. No posts have been deleted. Open ongoing discussions from the last week have been moved to either ASP.NET 1.0 and 1.1 Beginners http://p2p.wrox.com/asp-net-1-0-1-1-basics-60/ or ASP.NET 1.0 and 1.1 Professional. http://p2p.wrox.com/forum.asp?FORUM_ID=50. See my sticky post inside for more. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the ASP.NET 1.1 section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

February 27th, 2005, 02:46 AM
|
|
Friend of Wrox
|
|
Join Date: Apr 2004
Posts: 204
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
STUMPER of a Scope Problem (I think)
I'm pulling my hair out!
The full code is displayed below. Here is a summary of the problem:
In the declarations section I declare 5 public variables pertaining to an e-commerce order...
Public curTotal As Decimal
Public curTax As Decimal
Public curShipping As Decimal
Public strShippingMethod As String
Public curGrandTotal As Decimal
curTotal, curTax and curGrandTotal are assigned values as soon as the page loads.
curShipping and strShippingMethod, however, are assigned when the user selects a shipping method from a drop-down list ( the ddlShippingMethod_SelectedIndexChanged procedure).
All these values get put into session variables when the user hits the "finalize" button. The stumper is, curShipping always comes up as 0 and strShippingMethod comes up blank! This seems to be alleviated when I delcare these members as shared, rather than just public, but I heard I'm not supposed to do that (that other instances of the page could see the same shared members).
Also, why should everything work fine for curTotal and curTax, but not curShipping, when the two procedures use the exact same methodology?
Anyway here's the code. Thanks in advance for any and all help. This one is really perplexing.
Imports System.Data
Imports System.Data.SqlClient
Public Class WebForm1
Inherits System.Web.UI.Page
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
End Sub
Protected WithEvents lblOrder As System.Web.UI.WebControls.Label
Protected WithEvents Label1 As System.Web.UI.WebControls.Label
Protected WithEvents Label3 As System.Web.UI.WebControls.Label
Public cnxn As New SqlConnection
Protected WithEvents lblTotal As System.Web.UI.WebControls.Label
Protected WithEvents olblTotal As System.Web.UI.WebControls.Label
Protected WithEvents Label2 As System.Web.UI.WebControls.Label
Protected WithEvents olblShipping As System.Web.UI.WebControls.Label
Protected WithEvents Label4 As System.Web.UI.WebControls.Label
Protected WithEvents olblTax As System.Web.UI.WebControls.Label
Protected WithEvents btnCancel As System.Web.UI.WebControls.Button
Protected WithEvents btnFinalize As System.Web.UI.WebControls.Button
Protected WithEvents RequiredFieldValidator1 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents Label5 As System.Web.UI.WebControls.Label
Protected WithEvents olblGrandTotal As System.Web.UI.WebControls.Label
Protected WithEvents ddlShippingMethod As System.Web.UI.WebControls.DropDownList
Public curTotal As Decimal
Public curTax As Decimal
Public curShipping As Decimal
Public strShippingMethod As String
Public curGrandTotal As Decimal
'This is a general lable I use for sharing info about what various variables are doing.
Protected WithEvents lblError As System.Web.UI.WebControls.Label
'NOTE: The following placeholder declaration is required by the Web Form Designer.
'Do not delete or move it.
Private designerPlaceholderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DisplayOrderSummary()
End Sub
'This basically looks up an order from a database
'and accumulates the total value of the order
'then assigns the total to curTotal, the tax to curTax,
'and displays both on the screen
Private Sub DisplayOrderSummary()
Dim cookOrderID As HttpCookie
If Request.Cookies("OrderID") Is Nothing Then
Response.Redirect("CookieError.aspx")
End If
cookOrderID = Request.Cookies("OrderID")
Dim ProductIDList As String, QtyList As String
Dim a_ProductID(6) As String, a_ProductQty(6) As String
Dim a_ProductName(6) As String, a_ProductUnitPrice(6) As Decimal
Dim SQLOrderCommand As New SqlCommand
Dim SQLProductsCommand As New SqlCommand
Dim OrderReader As SqlDataReader
Dim ProductsReader As SqlDataReader
Dim strResults As String
Dim i As Integer, Rows As Int16
Dim curPrice As Decimal
cnxn.ConnectionString = "SERVER=xxx.xxx.xxx.xxx; DATABASE=xxxxxx;UID=xxx;pwd=xxxxxxxx;"
cnxn.Open()
SQLOrderCommand.CommandText = "SELECT * FROM tblOrders WHERE pkOrderID='" & cookOrderID.Value.ToString & "'"
SQLOrderCommand.Connection = cnxn
OrderReader = SQLOrderCommand.ExecuteReader
Do While OrderReader.Read
'Get ProductID and ProductQty list fields from the database
ProductIDList = OrderReader("txtProductIDList")
QtyList = OrderReader("txtQtyList")
'lblOrder.Text = lblOrder.Text & ProductIDList & "<br>"
Loop
OrderReader.Close()
'Put their contents into an array
a_ProductID = Split(ProductIDList, ",")
a_ProductQty = Split(QtyList, ",")
'Get all products from tblProducts
SQLProductsCommand.CommandText = "SELECT * FROM tblProducts"
SQLProductsCommand.Connection = cnxn
ProductsReader = SQLProductsCommand.ExecuteReader
i = 1
Do While ProductsReader.Read
a_ProductName(i) = ProductsReader("txtProductName")
a_ProductUnitPrice(i) = ProductsReader("curProductPrice")
i = i + 1
Loop
ProductsReader.Close()
'Put display table together
strResults = ""
strResults = strResults & "<Table style=""color:black; font-size: 8pt; line-Height:.8;"" cellpadding=0 border=0>"
strResults = strResults & "<tr style=""font-weight:bold;"">"
strResults = strResults & "<td width=10 align=Left>Qty.</td>"
strResults = strResults & "<td width=10></td>"
strResults = strResults & "<td width=100 align=center>Item</td>"
strResults = strResults & "<td width=90 align=right>Unit</td>"
strResults = strResults & "<td width=90 align=right>Price</td>"
strResults = strResults & "</tr>"
curTotal = 0
Rows = 0
For i = 0 To UBound(a_ProductID)
If a_ProductQty(i) > 0 Then
Rows = Rows + 1
strResults = strResults & "<tr height=15>"
strResults = strResults & "<td align=center>" & a_ProductQty(i) & "</td>"
strResults = strResults & "<td></td>"
strResults = strResults & "<td>" & a_ProductName(a_ProductID(i)) & "</td>"
strResults = strResults & "<td align=right>" & FormatCurrency(a_ProductUnitPrice(a_ProductID(i)), 2) & "</td>"
curPrice = a_ProductUnitPrice(a_ProductID(i)) * a_ProductQty(i)
curTotal = curTotal + curPrice
strResults = strResults & "<td align=right>" & FormatCurrency(curPrice, 2) & "</td>"
strResults = strResults & "</tr>"
End If
Next
strResults = strResults & "<tr><td colspan=5></td></tr>"
strResults = strResults & "</table>"
lblOrder.Text = strResults.ToString
olblTotal.Text = FormatCurrency(curTotal, 2)
curTax = curTotal * 0.0825
curGrandTotal = curTotal + curTax + curShipping
olblTax.Text = FormatCurrency(curTax, 2)
End Sub
'The preceding works fine. The public members curTotal, curTax and curGrandTotal are assigned, and are exposed to other procedures within the class, including the one below.
'This is the procedure that is screwing up.
'It assigns a value to curShipping, but that value doesn't
'show up when finalize is clicked.
Private Sub ddlShippingMethod_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ddlShippingMethod.SelectedIndexChanged
strShippingMethod = ddlShippingMethod.SelectedValue
'Use a simple breakdown of price to determine what the shipping cost should be.
'Note that this procedure can see the public member curTotal just fine, even though it was assigned a value inside another member procedure.
If curTotal <= 20 Then
curShipping = 4.95
ElseIf curTotal > 20 And curTotal <= 40 Then
curShipping = 6.95
ElseIf curTotal > 40 And curTotal <= 60 Then
curShipping = 8.95
ElseIf curTotal > 60 And curTotal <= 80 Then
curShipping = 10.95
ElseIf curTotal > 80 And curTotal <= 100 Then
curShipping = 12.95
ElseIf curTotal > 100 And curTotal <= 120 Then
curShipping = 14.95
Else
curShipping = 16.95
End If
lblError.Text = curShipping 'This displays the shipping cost on the screen
olblShipping.Text = FormatCurrency(curShipping, 2).ToString
curGrandTotal = curTotal + curTax + curShipping
olblGrandTotal.Text = FormatCurrency(curGrandTotal, 2).ToString
End Sub
'When the user clicks finalize, they usually get forwarded to
'a page where they can pay. I've got that disabled now, because the shipping thing is messed up.
Private Sub btnFinalize_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFinalize.Click
'This displays the curShippng public member again, when the user clicks the "finalize" button, BUT IT ALWAYS COMES UP AS 0!
lblError.Text = curShipping
Session("curTotal") = curTotal 'This works fine
Session("curTax") = curTax 'So does this
Session("curShipping") = curShipping 'This comes up as 0
Session("strShippingMethod") = strShippingMethod 'This comes up blank
'Response.Redirect("Finalize.aspx", True)
End Sub
End Class
|
|

February 27th, 2005, 05:22 AM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
|
|
Hi Aaron,
If I understand the problem correctly, this behavior is not so weird.
When you click the Finalize button, the page is posted back to the server. There, a new page is instantiated and your variables are assigned their default value (0 for an Integer, for example).
Since the list doesn't really change again, the OnChange is never fired, and the values are never changed.
To have the variables maintain their state after the second post back, you'll need to save them somewhere. ViewState is a good location, but Session variables might work as well....
HtH,
Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
|
|

February 28th, 2005, 12:51 PM
|
|
Friend of Wrox
|
|
Join Date: Apr 2004
Posts: 204
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Hi Imar,
So I think I'm beginning to get this.
I was perplexed by the fact that curTotal, curTax and curGrandTotal WERE persisting between postbacks--BUT THEY WEREN'T! I had forgotton to add the conditional expression
If Not IsPostBack Then
DisplayOrderSummary()
End If
to the onLoad event, so those variables were re-inventing themselves every time the page was reloaded--seeming to persist.
So, if I am understanding correctly, A CONTROL'S STATE will persist accross multiple postbacks (provided of course that the contol's EnableViewState property is set to True), but variables and members will not.
Is that roughly correct?
Why should I not use a control's Text propoerty then to manage my values between postbacks? For example, each variable I'm trying to mainitain (curTotal, curTax, curShipping and curGrandTotal) are displayed using labels. I could just use those labels' text properties. Is that bad programming practice?
Thanks once again, Imar.
Aaron
|
|

February 28th, 2005, 04:24 PM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
|
|
Yes, that is correct; controls can maintain their state, private variables and other members can't by default.
Personally, I wouldn't use a label for these kind of values. IMO, labels are for displaying data, not really for working with data. For example, you could add a currency symbol to your label for displaying purposes, while under the hood, you can't use that symbol. If you use the label's Text property directly, you would need to strip off the currency symbol.
I think one way to do it is to create public or protected properties on your class that maintain their state in View State, like this:
Code:
Public Property CurTotal() As Integer
Get
If Not ViewState("CurTotal") = Null Then
Return Convert.ToInt32(ViewState("CurTotal"))
Else
Return 0
End If
End Get
Set (ByVal Value As Integer)
ViewState("CurTotal") = Value
End Set
End Property
This way, you have properties that automatically maintain their state, while at the same time you have a clean programming interface.
If CurValue = 5 Then
looks much cleaner than:
If Convert.ToInt32(lblCurTotal.Text) = 5 Then
Cheers,
Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
|
|

March 1st, 2005, 09:53 PM
|
|
Friend of Wrox
|
|
Join Date: Apr 2004
Posts: 204
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks again, Imar. That worked beautifully.
Aaron
|
|
 |