Can't keep running totals - ASP.NET / VB - asp.net

I have an assignment to create a website that people can use to make dinner reservations. We are using Visual Basic code for the forms. It's supposed to keep running totals of each type of dinner. I'm having trouble getting the running totals to not reset to zero. I have them declared outside of the button click event. Not sure where I went wrong. Here's the code:
Option Strict On
Partial Class _Default
Inherits System.Web.UI.Page
Private Chicken_RT As Integer
Private Rib_RT As Integer
Private Veg_RT As Integer
Protected Sub SubmitButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubmitButton.Click
'Variables
Dim DinnerPrice As Integer
Dim RadioSelect As Boolean = True
Dim Tickets As Integer
Dim DinnerType As String
'Parsing
Tickets = Integer.Parse(TicketTextBox.Text)
'Validation / Calculations
If TicketRangeValidator.IsValid And TicketValidator.IsValid Then
If ChickenRadio.Checked = True Then
DinnerPrice = Tickets * 15
Chicken_RT += Tickets
DinnerType = "Chicken"
ElseIf RibRadio.Checked = True Then
DinnerPrice = Tickets * 20
Rib_RT += Tickets
DinnerType = "Rib"
ElseIf VegetarianRadio.Checked = True Then
DinnerPrice = Tickets * 12
Veg_RT += Tickets
DinnerType = "Vegetarian"
Else
RadioErrorLabel.Text = ("Please select a dinner type")
RadioSelect = False
End If
'Display results
If RadioSelect = True Then
If OpenBarCheckBox.Checked = True Then
DinnerPrice += Tickets * 15
OpenBarLabel.Text = "Yes"
Else
OpenBarLabel.Text = "No"
End If
NumberDinnersLabel.Text = Tickets.ToString()
DinnerTypeLabel.Text = DinnerType
TotalCostLabel.Text = DinnerPrice.ToString("C")
TotalChickenLabel.Text = Chicken_RT.ToString()
TotalRibLabel.Text = Rib_RT.ToString()
TotalVegetarianLabel.Text = Veg_RT.ToString()
End If
End If
End Sub
End Class

I have [the running totals] declared outside of the button click event.
Every time you handle an event, you're working with a new instance of your page class.
Understand that, and everything that's happening here should start to make sense to you. You must keep your totals in a place that persists across individual http requests, such as viewstate, the session, the application cache, on the file system, or in a database. Variables in your class to do not persist across individual http requests.

As Joel said, the values will not persist as each HTTP request creates a new instance of your class. The HiddenField Class would suit you nicely in this situation.
First, remove these lines of code:
Private Chicken_RT As Integer
Private Rib_RT As Integer
Private Veg_RT As Integer
Second, put this in your .aspx Markup (nested in the Form tag):
<asp:HiddenField id="Chicken_RT" runat="server" value="0"/>
<asp:HiddenField id="Rib_RT" runat="server" value="0"/>
<asp:HiddenField id="Veg_RT" runat="server" value="0"/>
Finally,
Veg_RT += Tickets
Becomes:
Veg_RT.Value = (CInt(Veg_RT.Value) + Tickets).ToString()
(Repeat for all of your running totals.)
To access your totals you would do:
Dim intVegTotal As Integer = CInt(Veg_RT.Value)

Well, I see you are reading TicketTextBox, but I don't see you assigning it any where. If you don't assign it, won't it's value always be zero?

Related

getting previous value before edition from textbox in gridview

I am applying edit functionality on gridview.
When my code's control is in rowupdating event, i am finding that i am getting previous value from textbox(i.e. value before i make edit in textbox).
Following is my code:
Protected Sub gvBooking_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles gvBooking.RowUpdating
'Dim name As String = DirectCast(gvBooking.Rows(e.RowIndex).FindControl("txtperson1"), TextBox).Text
Dim nname As String = (gvBooking.DataKeys(e.RowIndex).Values("person_name").ToString)
Dim id As Integer = Integer.Parse(gvBooking.DataKeys(e.RowIndex).Value.ToString)
Dim carname As String = gvBooking.DataKeys(e.RowIndex).Values("car_name").ToString
Dim carac As String = ""
'Dim sql As String = ""
'sql = "update dbo.tbl_Book set person_name='" + name + "',ac_type='" + carac + "' where booking_id = " + id.ToString
'gc.ExecuteCommand(sql)
'gvBooking.EditIndex = -1
'gc.BindGridView(gvBooking, "select * from tbl_Book")
End Sub
In this, if i edit person name from Henry to Scott and then press update button, then i finds through debugger that nname is having the value Henry only, which is the value before i make edit, instead it should have value Scott which i edited.
I am not understanding where i am making mistake.
Please help me.
After clicking Update, two events will be raised.
1.) GridView.Updating : Raised just before the Update is about to be committed.
In this event the data is still not updated in the Database. Basically this event is meant for some dynamic changes to be applied if required before the Update method actually commits the changed data to database.
2.) GridView.Updated
This event is raised immediately after data is updated. So it is in this event only that you put a debug symbol and check the Value. You will see your new value: Scott.
<asp:GridView ID="GridView1" runat="server" OnRowUpdated="GridView1_RowUpdated"></asp:GridView>
As you are checking the data when update is not made.That's why you are getting the original values only. Inside the GridView1_RowUpdated() method only check for the new values.
Also, still if you want to check your new values in Updating Event, Use GridViewUpdateEventArgs.NewValues Property [ e.Newvalues ] as : [ Check MSDN here ]
string s = e.NewValues[1].ToString(); // 2nd Column // c# sample

array not holding value when updated

i can add a value to array(0), but when i then add a value to array(1) it clears the value for array(0). I've tried every way I can think of to declare and create the array. My code looks like this:
Dim aryEstimateInfo() As String = New String(7) {}
Private Sub wzrdEstimateWizard_NextButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles wzrdEstimateWizard.NextButtonClick
Select Case wzrdEstimateWizard.ActiveStepIndex
Case 0 'first estimate wizard step
aryEstimateInfo(0) = rad_lstVehicleType.SelectedItem.ToString
Case 1 'second estimate wizard step
Dim DamageZoneSelected As Boolean = False
For Each cntrl As Control In pnlDamageZone.Controls
If TypeOf cntrl Is RadioButton Then
Dim RadButton As RadioButton = cntrl
If RadButton.Checked Then
DamageZoneSelected = True
DamageZone = RadButton.Text.ToString
Exit For
Else
DamageZoneSelected = False
End If
End If
Next
If DamageZoneSelected = True Then
lblDamageZoneError.Visible = False
aryEstimateInfo(1) = DamageZone
Else
'if no damage zone is selected a message is displayed
wzrdEstimateWizard.ActiveStepIndex = 2
wzrdEstimateWizard.ActiveStepIndex = 1
lblDamageZoneError.Visible = True
End If
Case 2 'third estimate wizard step
'assigns the number of dents to the estimate array
aryEstimateInfo(2) = ddlNumberOfDents.SelectedValue.ToString
'sets the average dent size in the estimate arrau
aryEstimateInfo(3) = ddlDentSize.SelectedValue.ToString
'sets the add-on code and number of oversized dents
If ddlOverSized.Enabled = True Then
'aryEstimateInfo.SetValue("3", 4)
aryEstimateInfo(4) = "3"
aryEstimateInfo(7) = ddlOverSized.SelectedValue.ToString
Else
End If
Case 3 'fourth estimate wizard step
Case Else
End Select
End Sub
I'm using this in an ASP.Net wizard control and in basic, visual studio 2010.
The problem is that each button click is posting back the page, which causes your aryEstimateInfo to be re-created on each postback.
In order to handle this situation elegantly, improve the maintenance of the page, and make it easier to debug this sort of situation in the future, I recommend the following changes:
1) Change the array to a class with properties:
Public Class EstimateInfo
Public VehicleType As String = ""
Public DamageZone As String = ""
Public NumberOfDents As String = ""
Public DentSize As String = ""
Public AddOnCode As String = ""
Public Oversized As String = ""
End Class
Note that all of the properties are declared as string, but the data types should probably be changed to more accurately reflect the underlying content.
This approach will help debugging because you can change the auto-implemented property to a getter/setter so that you can place a breakpoint to see where the value is getting cleared:
Private m_sVehicleType As String = ""
Public Property VehicleType As String
Get
Return m_sVehicleType
End Get
Set (Value As String
' You could set a breakpoint here to discover where the value is getting cleared.
m_sVehicleType = Value
End Set
End Property
And if you need to have the values in a string array for export to a different application or database, for example, you could add a method to the class to produce an appropriate string array.
2) Add a property to the page to store the current answer class in the page's ViewState so that you won't have to continuously re-populate the array. For example:
Private Property EstimateInfo As EstimateInfo
Get
' Add a new record to the viewstate if it doesn't already exist
If ViewState("EstimateInfo") Is Nothing Then
Me.EstimateInfo = New EstimateInfo
End If
Return ViewState("EstimateInfo")
End Get
Set (value As EstimateInfo)
ViewState("EstimateInfo") = value
End Set
End Property
Once you do this, your wizard code becomes much easier to understand and maintain:
Select Case wzrdEstimateWizard.ActiveStepIndex
Case 0 'first estimate wizard step
Me.EstimateInfo.VehicleType = rad_lstVehicleType.SelectedItem.ToString
when you declare the new array someehere in the code you cannot reuse it again after post back.
I suggest to build the array on finish wizard event
you can use the controls in whole steps where ever step you in
I guess it will be fine
otherwise you need to store the array after every update in session or view state but I don't like both
sorry I couldn't view example becoz I'm using mobile

System.ArgumentException: String value can not be converted to a date

I have a web form that uses an Ajax date calendar. This works fine. The problem that i have is that when i submit my form i get the following message.
'String value can not be converted to a date' .AgendaDate = New SmartDate(txtAgendaDate.Text)
Here is my web form that holds the calendar and the associated text box...
<td>
<asp:TextBox ID="txtAgendaDate" runat="server" ForeColor="Black" ></asp:TextBox>
</td>
<td>
<asp:ImageButton runat="Server" ID="ImageButton1" ImageUrl="~/images/calendarpic.png"
AlternateText="Click here to display calendar" />
<cc1:calendarextender ID="CalendarExtender1" runat="server"
TargetControlID="txtAgendaDate" PopupButtonID="ImageButton1" >
</cc1:calendarextender>
</td>
I have a class with the associated properties on it for the web form. The rest of the fields work and submit data to the database except the textfield for the ajax calendar.
Here is my stripped down version for the code for the class and the txtAgendaDate code...
#Region " Agenda Variables "
'Declare Variables and data types and set default values
Private mAgendaID As Integer = 0
Private mOrganiser As String = ""
Private mMeeting As String = ""
Private mAgendaDate As SmartDate = New SmartDate()
#End Region
#Region " Constructors "
Public Sub New()
End Sub
Public Sub New(ByVal reader As SafeDataReader)
' Public Sub New(ByVal reader As SQLDataReader)
'Combine variables & property types
With reader
mAgendaID = .GetInt32("AgendaID")
mOrganiser = .GetString("Organiser")
mMeeting = .GetString("Meeting")
mAgendaDate = .GetSmartDate("AgendaDate")
End With
End Sub
#End Region
#Region "Properties"
'Define form field properies so that they can be used when adding the data to the database on the add button is pressed.
Public Property AgendaID() As Integer
Get
Return mAgendaID
End Get
Set(ByVal Value As Integer)
mAgendaID = Value
End Set
End Property
Public Property Organiser() As String
Get
Return mOrganiser
End Get
Set(ByVal value As String)
mOrganiser = value
End Set
End Property
Public Property Meeting() As String
Get
Return mMeeting
End Get
Set(ByVal value As String)
mMeeting = value
End Set
End Property
Public Property AgendaDate() As SmartDate
Get
Return mAgendaDate
End Get
Set(ByVal Value As SmartDate)
mAgendaDate = Value
End Set
End Property
#End Region
End Class
Here is my command that looks connects to the DB and at the stored procedure and also has the parameters.
Public Class Agenda_TempDAL
Public Shared Function AddAgenda_Temp(ByVal Agenda_Temp As Agenda_Temp) As Integer
'Declare i as integer as 0
Dim iAgendaID As Integer = 0
'Database conn, this is linked to the web config file .AppSettings
Using dbconnection As New SqlConnection(ConfigurationManager.AppSettings("dbconnection"))
dbconnection.Open()
'Command to state the stored procedure and the name of the stored procedure
Using dbcommand As SqlCommand = dbconnection.CreateCommand
With dbcommand
.CommandType = CommandType.StoredProcedure
.CommandText = "Stored_Proc_Name"
'Create parameter for AgendaID and output
Dim oParam As New SqlParameter
oParam.ParameterName = "#AgendaID"
oParam.Direction = ParameterDirection.Output
oParam.SqlDbType = SqlDbType.Int
'Create parameters for the remaining fields
.Parameters.Add(oParam)
.Parameters.AddWithValue("#Organiser", Agenda_Temp.Organiser)
.Parameters.AddWithValue("#Meeting", Agenda_Temp.Meeting)
.Parameters.AddWithValue("#AgendaDate", Agenda_Temp.AgendaDate.DBValue)
'Simply execute the query
dbcommand.ExecuteNonQuery()
End With
End Using
End Using
'Need to return the agendaID as an integer.
Return iAgendaID
End Function
End Class
And here is the code behind the button ion the web page. This is the page that causes the error based on the property / field. The problem lies on this line...
.AgendaDate = New SmartDate(txtAgendaDate.Text)
The whole code for the button is here...
Protected Sub btnAddAgendaTemplate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddAgendaTemplate.Click
'This works alongside the Class named Agenda_Temp which has the properties and DB connection assigned to it for each web form field.
Dim oAgenda_Temp As New Agenda_Temp
'Within the object Agenda_Temp Class use the properties defined.
'They are required to be defined in the Agenda_Temp/ app code so we can use them within here.
With oAgenda_Temp
.Organiser = txtOrganiser.Text
.Meeting = txtMeeting.Text
.AgendaDate = New SmartDate(txtAgendaDate.Text)
'Within the object Agenda_Temp class use the defined DAL which includes all the DC connect and stored procedures.
oAgenda_Temp.AgendaID = Agenda_TempDAL.AddAgenda_Temp(oAgenda_Temp)
End With
End Sub
End Class
I understand that its telling me that the string value cannot be converted to a date but i don't know hoe to resolve this as i am new to .net 2010?
Any help much appreciated.
Convert the string to a date before newing it:
From MSDN:
string date = "01/08/2008";
DateTime dt = Convert.ToDateTime(date);
Your's would become
DateTime dt = Convert.ToDateTime(txtAgendaDate.Text)
Then pass the date to your SmartDate constructor:
oAgenda_Temp.AgendaDate = new SmartDate(dt)
The final result:
With oAgenda_Temp
.Organiser = txtOrganiser.Text
.Meeting = txtMeeting.Text
.AgendaDate = New SmartDate(Convert.ToDateTime(txtAgendaDate.Text))
'Within the object Agenda_Temp class use the defined DAL which includes all the DC connect and stored procedures.
oAgenda_Temp.AgendaID = Agenda_TempDAL.AddAgenda_Temp(oAgenda_Temp)
End With
As others have pointed out, you need to convert the input value to a DateTime. I don't know what the SmartDate() function is doing, but the error message clearly indicates that the value cannot be converted to a date.
Secondly, I would add some validation to make sure that the input is valid before you submit the page. Use the RequiredFieldValidator and CompareValidator or RegularExpressionValidator:
<asp:TextBox ID="txtDate" runat="server" ... />
<asp:RequiredFieldValidator ID="reqDate" runat="server" ErrorMessage="Required" Display="Dynamic" ControlToValidate="txtDate"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="regDate" runat="server" ControlToValidate="txtDate" ErrorMessage="Please enter a valid date in the format (mm/dd/yyyy)" ValidationExpression="^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$"></asp:RegularExpressionValidator>

ASP CascadingDropDown Control Causes IE Script timeout

Before a page is loaded, I use a subroutine to link DropDownList controls together:
Private Sub CreateCascadingDropDown(ByVal category As String, ByRef parentDDL As DropDownList, ByRef targetDDL As DropDownList)
Dim CDDL As New CascadingDropDown
With CDDL
.Category = category
If Not parentDDL Is Nothing Then
parentDDL.Items.Clear()
.ParentControlID = parentDDL.ID
End If
targetDDL.Items.Clear()
.TargetControlID = targetDDL.ID
.PromptText = SharedWeb.GC_SELECTONE
.PromptValue = "-1"
.LoadingText = "Please wait..."
.ServicePath = "/ajax/InvestmentProcess.asmx"
.ServiceMethod = "GetTaxo"
End With
'Page.ClientScript.RegisterForEventValidation(CDDL.UniqueID)
targetDDL.Parent.Controls.Add(CDDL)
End Sub
When the web service method is called, it executes the following code. Based on the category, it gets the appropriate data from the adapter.
<WebMethod()> _
Public Function GetTaxo(ByVal knownCategoryValues As String, ByVal category As String) As CascadingDropDownNameValue()
Dim log As ILog = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
log.Debug("GetSegmentTaxonomy(" + category + ") -> {" + knownCategoryValues + "}")
Dim kv As StringDictionary = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues)
Dim adapter As New SegmentTaxonomyTableAdapters.SEGMENT_ARCHITECTURE_TableAdapter
Dim rows As DataRowCollection
Select Case category
Case InvestmentEdit.ST_SEG_ARCH
rows = New SegmentTaxonomyTableAdapters.SEGMENT_ARCHITECTURE_TableAdapter().GetData().Rows
Case InvestmentEdit.ST_LOB
If kv.ContainsKey(InvestmentEdit.ST_SEG_ARCH) Then
log.Debug("found seg architecture - > " + kv(InvestmentEdit.ST_SEG_ARCH))
rows = New SegmentTaxonomyTableAdapters.LINE_OF_BUSINESSTableAdapter().GetData(kv(InvestmentEdit.ST_SEG_ARCH)).Rows
End If
End Select
If Not rows Is Nothing Then
Dim results As New List(Of CascadingDropDownNameValue)
For Each row As DataRow In rows
log.Debug("ROW >>>> " + row("lov_label").ToString() + " : " + row("lov_cd").ToString())
results.Add(New CascadingDropDownNameValue(row("lov_label"), row("lov_cd")))
Next
Return results.ToArray
End If
Return Nothing
End Function
There are about 5 drop downs I need to link together. The top-level drop down control (myDDL) loads fine if it is the only one linked like so:
CreateCascadingDropDown("MyCat",Nothing,myDDL)
But when I link a second drop down control, Internet Explorer gives a script timeout. If I keep allowing the script to run, it just keeps giving me the prompt. If elect to discontinue running the script, I get a Method Error 12031 or Error 500 (and yes, I have the ScriptService() declaration in my web service file). Any ideas on what's causing this?
It turns out I just needed to add the following control from the Ajax Control Toolkit:
<ajax:ToolkitScriptManager ID="tsm" runat="server" />
Instead of .TargetControlID = targetDDL.ID I needed to use:
.TargetControlID = targetDDL.UniqueId

Asp.Net Button Event on refresh fires again??? GUID?

The obvious issue here is that on refresh a button event is recalled and duplicate posts are created in the database. I have read other questions on this site about the very same issue.
Apparently the answer is for every post create a GUID and check to make sure the GUID is unique? I am not really sure how to implement this.
Does that mean on refresh, it will try and create a duplicate post with the same GUID?
How do you implement a GUID into your database? Or if this is not the answer, what is?
Thank you!
The idea is that you create a unique number for the form, and when the form is posted you save this unique number in the database in the record that you are editing/creating. Before saving you check if that number has already been used, in that case it's a form that has been reposted by refreshing.
If you are updating a record, you only have to check if that record has been saved with the same unique number, but if you are adding a new record you have to check if any other record has that number.
A Guid is a good number to use as it's very unlikely that you get a duplicate. A 31 bit random number that the Random class can produce is also pretty unlikely to give duplicates, but the 128 bits of a Guid makes it a lot more unlikely.
You don't have to create the Guid value in the database, just use Guid.NewGuid() in the code that initialises the form. You can put the Guid in a hidden field in the form. In the database you only need a field that can store a Guid value, either a Guid data type if available or just a text field large enough to hold the text representation of the Guid.
You can use the ToString method to get the string representation of a Guid value (so that you can put it in the form). Using id.ToString("N") gives the most compact format, i.e. 32 hexadecimal digits without separators. Using id.ToString("B") gives the more recognisable format "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}". To get the Guid back from a string (either format), you just use new Guid(str).
Here's a RefreshValidator control that I use. Just drop it on your page, and check Page.IsValid before saving to the database. You can add an error message like other validators, or catch the Refreshed event if you want to do something special. Since it's a Validator, GridViews and the like will already take notice of it - except for Delete or Cancel actions (yeah, I have a custom GridView that solves that too...)
The code is pretty simple - store a GUID into ControlState, and a copy in Session. On load, compare the 2. If they're not the same - then it's a refresh. Rinse, repeat, and create a new GUID and start over.
''' <summary>
''' A validator control that detects if the page has been refreshed
''' </summary>
''' <remarks>If <see cref="SessionState.HttpSessionState" /> is not available or is reset, validator will return Valid</remarks>
Public Class RefreshValidator
Inherits BaseValidator
Private isRefreshed As Boolean
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
MyBase.OnInit(e)
Page.RegisterRequiresControlState(Me)
End Sub
Protected Overrides Function SaveControlState() As Object
Dim obj As Object = MyBase.SaveControlState()
Return New System.Web.UI.Pair(_pageHashValue, obj)
End Function
Protected Overrides Sub LoadControlState(ByVal savedState As Object)
Dim pair As System.Web.UI.Pair = TryCast(savedState, System.Web.UI.Pair)
If pair IsNot Nothing Then
_pageHashValue = TryCast(pair.First, String)
MyBase.LoadControlState(pair.Second)
Else
MyBase.LoadControlState(savedState)
End If
End Sub
Private _pageHashValue As String
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
If HttpContext.Current Is Nothing OrElse HttpContext.Current.Session Is Nothing Then
isRefreshed = False
Return
End If
' Get hash value from session
Dim currHashValue As String = CType(HttpContext.Current.Session(Me.UniqueID & ":pageHashValue"), String)
If _pageHashValue Is Nothing OrElse currHashValue Is Nothing Then
' No page hash value - must be first render
' No current hash value. Session reset?
isRefreshed = False
ElseIf currHashValue = _pageHashValue Then
' Everything OK
isRefreshed = False
Else
' Was refreshed
isRefreshed = True
End If
' Build new values for form hash
Dim newHashValue As String = Guid.NewGuid().ToString()
_pageHashValue = newHashValue
HttpContext.Current.Session(Me.UniqueID & ":pageHashValue") = newHashValue
End Sub
Protected Overrides Function ControlPropertiesValid() As Boolean
Return True
End Function
Protected Overrides Function EvaluateIsValid() As Boolean
If isRefreshed Then OnRefreshed(EventArgs.Empty)
Return Not isRefreshed
End Function
Protected Overridable Sub OnRefreshed(ByVal e As EventArgs)
RaiseEvent Refreshed(Me, e)
End Sub
''' <summary>
''' Fires when page is detected as a refresh
''' </summary>
Public Event Refreshed As EventHandler
End Class

Resources