Wrox Programmer Forums
Go Back   Wrox Programmer Forums > ASP.NET and ASP > ASP.NET 1.0 and 1.1 > ASP.NET 1.1
|
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
 
Old February 27th, 2005, 02:46 AM
Friend of Wrox
 
Join Date: Apr 2004
Posts: 204
Thanks: 0
Thanked 0 Times in 0 Posts
Default 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


 
Old February 27th, 2005, 05:22 AM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

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.
 
Old February 28th, 2005, 12:51 PM
Friend of Wrox
 
Join Date: Apr 2004
Posts: 204
Thanks: 0
Thanked 0 Times in 0 Posts
Default

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

 
Old February 28th, 2005, 04:24 PM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

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.
 
Old March 1st, 2005, 09:53 PM
Friend of Wrox
 
Join Date: Apr 2004
Posts: 204
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thanks again, Imar. That worked beautifully.

Aaron






Similar Threads
Thread Thread Starter Forum Replies Last Post
Scope of Objects Handman BOOK: Professional C# 2008 ISBN: 978-0-470-19137-8 12 October 20th, 2008 10:06 AM
Visual Studio 2005 FrontPage Extensions Stumper buckycore ASP.NET 1.0 and 1.1 Basics 0 November 28th, 2007 02:02 PM
Iterator Scope Problem smokey_gun Javascript How-To 1 July 4th, 2007 01:26 AM
Scope resolution problem _fluffy_ BOOK: ASP.NET 2.0 Website Programming Problem Design Solution ISBN: 978-0-7645-8464-0 2 October 16th, 2006 09:37 AM
scope problem jc Javascript 0 July 29th, 2003 09:27 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.