Most efficient way to validate multiple textboxes against a tolerance value - asp.net

I have a series of text boxes in a table to gather input as below:
The user will input a target and actual value for each measurement point they require. I would then like to validate the actual values against the target values based upon the tolerance inputted in the tolerance textbox. The tolerance will be the same for all measurement points inputted, however the user will not always input all 10 measurement points.
I have also created a very basic class containing a function that accepts the target, actual and tolerance values then returns a Boolean depending on whether the actual value is within tolerance. I realise I could use this with a ruck load of if statements to check each textbox for input then use the class to perform the validation, however this seems like a lot of code repetition and a bit crude. My question being is there a better way I can perform this validation?
EDIT Class content
Public Class TolerenceHelper
Public Function IsInTolerence(ByVal target As Integer, ByVal actual As Integer, ByVal tolerence As Integer) As Boolean
Dim upper As Integer = target + tolerence
Dim lower As Integer = target - tolerence
If actual < lower OrElse actual > upper Then
Return False
Else
Return True
End If
End Function
Calling the function as below:
Dim m1 As TolerenceHelper
Dim flag As Boolean = True
m1 = New TolerenceHelper
If m1.IsInTolerence(Integer.Parse(txtT1.Text), Integer.Parse(txtA1.Text), Integer.Parse(txtTolerance.Text)) = False Then
flag = False
End If
If flag = False Then
lblTest.Text = "Out of tolerance"
Else
lblTest.Text = "In tolerance"
End If

Your helper method seems to be ok, but you haven't shown the important part that you want to improve. The part where you load all textboxes and check whether they are valid or not.
Here is an approach that uses a custom class Measurement. You can use
Math.Abs(target.Value - actual.Value) <= tolerance
to determine if the value is valid according to the target and the tolerance.
Public Class Measurement
Public Property Tolerance As Int32
Public Property Target As Int32
Public Property Value As Int32
Public ReadOnly Property IsValid As Boolean
Get
Return Math.Abs(Target - Value) <= Tolerance
End Get
End Property
End Class
I would add all textboxes into the same container control like a Panel. Then you could use Enumerable.OfType to find the relevant textboxes. I use Enumerable.Zip to bring the values and the targets together. Use Int32.TryParse to validate the text.
Dim tolerance As Int32
If Not Int32.TryParse(txtTolerance.Text, tolerance) Then
lblTest.Text = "Enter a valid tolerance! Tolerance must be a positive integer(incl. zero)."
Return
End If
Dim value As Int32
Dim allTxtTarget = From txt In Me.PnlMeasurement.Controls.OfType(Of TextBox)()
Where txt.ID Like "txtT#*" AndAlso Int32.TryParse(txt.Text, value)
Let x = New With {.TextBox = txt, .Value = value, .Type = "Target", .Number = txt.ID.Substring(4)}
Order By x.Number
Select x
Dim allTxtActual = From txt In Me.PnlMeasurement.Controls.OfType(Of TextBox)()
Where txt.ID Like "txtA#*" AndAlso Int32.TryParse(txt.Text, value)
Let x = New With {.TextBox = txt, .Value = value, .Type = "Value", .Number = txt.ID.Substring(4)}
Order By x.Number
Select x
Dim allMeasurements = allTxtTarget.Zip(allTxtActual,
Function(target, actual) New Measurement With {
.Tolerance = tolerance,
.Target = target.Value,
.Value = actual.Value
}).ToList()
Output the results:
For i As Int32 = 0 To allMeasurements.Count - 1
Dim m = allMeasurements(i)
Console.WriteLine("Measurement {0}: Tolerance:{1} Target:{2} Value:{3} Valid:{4}",
i+1, tolerance, m.Target, m.Value, m.IsValid)
Next
If you actually need to check if all or at least one measurement is valid you can use:
Dim allValid = allMeasurements.All(Function(m) m.IsValid)
Dim anyValid = allMeasurements.Any(Function(m) m.IsValid)
or to find the highest valid measurement:
Dim validMeasurements = From m In allMeasurements
Where m.IsValid
Order By m.Value Descending
Dim highestMeasurement = validMeasurements.FirstOrDefault()

Related

Getting "Not a legal OleAut date" error with AutoFitColumns function in EPPlus

I'm exporting some data to Excel using the EPPlus library. After writing the data to the cells, I call the AutofitColumns function. This throws an error:
Exception of type 'System.Web.HttpUnhandledException' was thrown.; Not a legal OleAut date.;
STACK: at System.DateTime.TicksToOADate(Int64 value)
at OfficeOpenXml.ExcelRangeBase.FormatValue(Object v, ExcelFormatTranslator nf, String format, String textFormat)
at OfficeOpenXml.ExcelRangeBase.AutoFitColumns(Double MinimumWidth, Double MaximumWidth) at OfficeOpenXml.ExcelRangeBase.AutoFitColumns()
at ExcelHelper.SetExcelSettings(ExcelWorksheet& aSheet, Int32 AutoFilterRow, Int32 AutoFilterColumn, Int32 ColNumber, Int32 ColWidth)
at RLog.Export(Int32 aOfficeID, Boolean aInco...
It seems to be caused by a specific value in the data, because it works for other ranges of data. But I cannot figure out which exact data. Also, I can't understand why AutoFitColumns has to call FormatValue.
Any idea as to what can cause this? Here is the code:
Public Shared Sub SetExcelSettings(ByRef aSheet As ExcelWorksheet, Optional AutoFilterRow As Integer = 0, Optional AutoFilterColumn As Integer = 0, Optional ColNumber As Integer = 0, Optional ColWidth As Integer = 0)
' Apply formatting to excel
If aSheet.Dimension IsNot Nothing Then
With aSheet
'.View.ShowGridLines = False
If AutoFilterRow > 0 Then .Cells(AutoFilterRow, 1, AutoFilterRow, aSheet.Dimension.End.Column).AutoFilter = True
.Cells(.Dimension.Address).AutoFitColumns() ' Error happens here
' Wrap the text for Remarks fields
.Cells(.Dimension.Address).Style.WrapText = True
.Cells(.Dimension.Address).Style.VerticalAlignment = Style.ExcelVerticalAlignment.Center
' Set the specified width and auto wrap for specified column
If ColNumber > 0 Then .Column(ColNumber).Width = ColWidth : .Column(ColNumber).Style.WrapText = True
End With
End If
End Sub

How to convert a "custom class" to an arraylist?nc

I have a class called student. Student class has public fields like first name, and last name. I am creating an instance of this class in my default page and assigning values to the fields. I have a function which takes two arraylists and return false if items in the arraylists do not match. In my default page, I have an arraylist which has items like first name and last name. I am passing this student object and the arraylist to compare and I get unable to cast Student to arraylist. Is there a way to work around this? Below is my code.
Dim valid as boolean = StudentsCompare(Student, arrlst)
Function StudentsCompare(ByVal arraylist1 as Arraylist, ByVal arrayList2 as ArrayList)
Dim Error As Boolean = True
For i As Integer = 0 To (arraylist1.Count - 1)
If Not arraylist1.Item(i).ToString = arrayList2.Item(i).ToString Then
Return Error = False
End If
Next
Return Error
End Function
You could do it this way; student.FirstName is an example you may need to change it with one of your class's real property.
Private valid As Boolean = StudentsCompare(List(Of Student), arrlst)
Private Function StudentsCompare(students As List(Of Student), list As ArrayList) As Boolean
Dim index As Integer = 0
For Each student As var In students
If student.FirstName = list(index).ToString() Then
Return False
End If
index += 1
Next
Return True
End Function
And If you have both parameter with the same object "Student" you could do it this way and check the multiple conditions:
Private list1 As List(Of Student)
Private list2 As List(Of Student)
Private valid As Boolean = StudentsCompare(list1, list2)
Private Function StudentsCompare(students1 As List(Of Student), students2 As List(Of Student)) As Boolean
For Each st1 As var In students1
For Each st2 As var In students2
If st1.FirstName = st2.FirstName AndAlso st1.LastName = st2.LastName AndAlso st1.Grade = st2.Grade Then
Return True
End If
Next
Next
Return False
End Function

How to fill all textboxes after click on gridview by making classLibrary?

I want to make a class library containing classes for common tasks.
I made such a class that worked very well on some forms but it have some errors that I can't trace down.
This is my code and it does the following:
It accepts 3 parameters: form name, datagridview name and the textbox name prefixes.
It counts the datagrid columns
It takes the current row index
It makes the array with a length corresponding to the number of columns
It's looking in the form for all text boxes that have a name with prefix parameter + column name and set the value in it
Code:
Sub setRecordFieldToControl(ByVal root As Form, ByVal dgv As DataGridView, ByVal cntrlPreNam1 As String, ByVal cntrlPreNam2 As String)
Dim j, k, z As Integer
Dim s As String
z = dgv.ColumnCount
k = dgv.CurrentRow.Index
j = 0
Dim headTxt(z) As String
For indx = 0 To z - 1
headTxt(indx) = dgv.Columns(indx).HeaderText
Next
For Each i As Control In root.Controls
If TypeOf i Is MaskedTextBox Or TypeOf i Is ComboBox Then
For clm = 0 To z
If i.Name = cntrlPreNam1 & headTxt(clm) Or i.Name = cntrlPreNam1 & headTxt(clm) Then
s = (dgv.Rows(k).Cells(j).Value)
i.Text = s
' i.Text = dgv.Item(j, k).Value
j = j + 1
If j >= z Then
Exit For
End If
End If
Next
End If
Next
End Sub
My problem is: on some forms I got this error:
Index is out of range for line i.Text = s
The error does not show up when I put something else in my text box, the error only appears when I put the s in it.
The error is probably in the line
For clm = 0 To z
It should read
For clm = 0 To z - 1
The column indexes range from 0 .. number_of_columns - 1.
UPDATE
There are several problems with your code:
The logic seems wrong to me. You are looking for the column (clm) with the right name but then take the value of another column (j). Why?
The variable names are not speaking and are even misleading (e.g. i for a Control).
You have nested loops with an O(n^2) behavior. See Big O Notation.
I suggest rewriting it. Use a dictionary for the possible control names, that stores the corresponding column indexes by name. Dictionaries have a nearly constant access speed. In other words: Lookups are very fast.
Sub SetRecordFieldToControl(ByVal root As Form, ByVal dgv As DataGridView, _
ByVal cntrlPrefix1 As String, ByVal cntrlPrefix2 As String)
Dim currentRowIndex As Integer = dgv.CurrentRow.Index
Dim columnDict = New Dictionary(Of String, Integer)
For i As Integer = 0 To dgv.ColumnCount - 1
Dim headerText As String = dgv.Columns(i).HeaderText
columnDict.Add(cntrlPrefix1 & headerText, i)
columnDict.Add(cntrlPrefix2 & headerText, i)
Next
For Each cntrl As Control In root.Controls
If TypeOf cntrl Is MaskedTextBox Or TypeOf cntrl Is ComboBox Then
Dim columnIndex As Integer
If columnDict.TryGetValue(cntrl.Name, columnIndex) Then
Dim value As Object
value = dgv.Rows(currentRowIndex).Cells(columnIndex).Value
If Not value Is Nothing Then
cntrl.Text = value.ToString()
End If
End If
End If
Next
End Sub

Looping through textboxes and labels

Im doing this project for an online test in ASP.NET in VB im using Microsoft visual studios 2012.
Im trying to get a loop going through my textboxes and check them against a word this will be change to be validated against a database to see if the answer are correct but when I do my loop I cannot get my text from the textbox.
Please see below
Private Sub GoGoGo()
Dim Textboxname As String '
Dim textbox As Object
Dim TextboxText As Object
Dim Labelname As String
Dim label As Object
Dim LabelText As Object
Dim Number As Integer = 1
Dim MaxTime As Integer = 9
Dim Currentloop As Integer = 1
For check As Integer = Currentloop To MaxTime
If Currentloop <= MaxTime Then
Textboxname = "TextQ" + Number
textbox = Textboxname
TextboxText = textbox
textbox.ReadOnly = True
End If
If Currentloop <= MaxTime Then
Labelname = "Label" + Number
label = Labelname
LabelText = label.Text
label.Visible = True
End If
Number = Number + 1
If TextboxText = "" Then
label.Text = "no imput"
label.ForeColor = Drawing.Color.Black
End If
If TextboxText = "server" Then
label.Text = "Correct"
label.ForeColor = Drawing.Color.Green
End If
If TextboxText = "Wrong" Then
label.Text = "Wrong"
label.ForeColor = Drawing.Color.Red
End If
If check = 9 Then
Exit For
End If
Next
End Sub
It looks like you are trying to use the string identifier of the control in place of the the actual control. Instead, you should take this identifier and search for the actual control on the page. You can do this using the FindControl method
Your function would therefore look something like (not compile tested):
Private Sub GoGoGo()
'
Dim oTextBox As TextBox
Dim oLabel As Label
Dim MaxTime As Integer = 9
Dim Currentloop As Integer = 1
For check As Integer = Currentloop To MaxTime
If Currentloop <= MaxTime Then
'NB You may have to use a recursive call to FindControl. See below.
oTextBox = CType(Page.FindControl("TextQ" & CStr(check)), TextBox)
OTextBox.ReadOnly = True;
End If
If Currentloop <= MaxTime Then
'NB You may have to use a recursive call to FindControl. See below.
oLabel = CType(Page.FindControl("Label" & CStr(check)), Label)
oLabel.Visible = True
End If
If oTextBox.Text = "" Then
oLabel.Text = "no imput"
oLabel.ForeColor = Drawing.Color.Black
End If
If oTextBox.Text = "server" Then
oLabel.Text = "Correct"
oLabel.ForeColor = Drawing.Color.Green
End If
If oTextBox.Text = "Wrong" Then
oLabel.Text = "Wrong"
oLabel.ForeColor = Drawing.Color.Red
End If
Next
End Sub
Some notes:
You don't need all of those variables. Instead, just find the actual controls, and interact with the properties directly - just check the TextBox.Text value when you need to, and set the Label.text property directly. The set is especially important as you want to update the original control property so it is shown on the page.
Similarly, you don't need Number - you can use check as this is your loop counting variable.
Whether you use the + operator or the & operator for string concatenation is up to you. There's already a good question and several answers here.
You also don't need the exit condition for the loop - the loop will exit as soon as you reach MaxTime. If you want it to exit early, just vary your To condition (e.g. Currentloop To MaxTime - 1)
UPDATE:
Page.FindControl will only work with controls that are immediate children of the root element on the page. Instead, you should try calling FindControl recursively. You should also make sure that a control with the id TextQ1 exists - look in the HTML source for the page on the client to make sure a TextBox with this id exists.
There are many examples of this on the net. Here's a VB.Net version (source: http://www.pavey.me/2007/09/recursive-pagefindcontrol-for-vbnet.html) that you can add to your page:
Public Function FindControlRecursive(Of ItemType)(ByVal Ctrl As Object, ByVal id As String) As ItemType
If String.Compare(Ctrl.ID, id, StringComparison.OrdinalIgnoreCase) = 0 AndAlso TypeOf Ctrl Is ItemType Then
Return CType(Ctrl, ItemType)
End If
For Each c As Control In Ctrl.Controls
Dim t As ItemType = FindControlRecursive(Of ItemType)(c, id)
If t IsNot Nothing Then
Return t
End If
Next
Return Nothing
End Function
Your line in the code above would then become:
oTextBox = FindControlRecursive(of TextBox)(Page.Controls(0), "TextQ" & CStr(check))
You'd also need to do the same for the Label control.
It Look like you are using only name istead of textbox try with the code below
Private Sub GoGoGo()
Dim Textboxname As String '
Dim textbox As TextBox
Dim TextboxText As Object
Dim Labelname As String
Dim label As Object
Dim LabelText As Object
Dim Number As Integer = 1
Dim MaxTime As Integer = 9
Dim Currentloop As Integer = 1
For check As Integer = Currentloop To MaxTime
If Currentloop <= MaxTime Then
Textboxname = "TextQ" + Number
textbox = Ctype(Me.Controls(Textboxname), TextBox)
TextboxText = textbox.Text
textbox.ReadOnly = True
End If
If Currentloop <= MaxTime Then
Labelname = "Label" + Number
label = Labelname
LabelText = label.Text
label.Visible = True
End If
Number = Number + 1
If TextboxText = "" Then
label.Text = "no imput"
label.ForeColor = Drawing.Color.Black
End If
If TextboxText = "server" Then
label.Text = "Correct"
label.ForeColor = Drawing.Color.Green
End If
If TextboxText = "Wrong" Then
label.Text = "Wrong"
label.ForeColor = Drawing.Color.Red
End If
If check = 9 Then
Exit For
End If
Next
End Sub

Filter records based on Date Range + ASP.NET + Regex + Javascript

I need to filter data based on a date range.
My table has a field Process date. I need to filter the records and display those in the range FromDate to ToDate.
How do I write a function in VB.NET which can help me filter the data.
Am I on the right track??
Why dont you do yourself a favor and DateTime.Parse your strings and use Date comparison operators
Something like
Function ObjectInRange(ByRef obj As Object, ByVal str1 As String, ByVal str2 As String) As Boolean
Dim date1 As DateTime = DateTime.Parse(str1)
Dim date2 As DateTime = DateTime.Parse(str2)
Dim inRange = False
For Each prop As PropertyInfo In obj.GetType().GetProperties()
Dim propVal = prop.GetValue(obj, Nothing)
If propVal Is Nothing Then
Continue For
End If
Dim propValString = Convert.ToString(propVal)
Dim propValDate = DateTime.Parse(propValString)
If propValDate.CompareTo(date1) > 0 And propValDate.CompareTo(date2) < 0 Then
inRange = True
Exit For
End If
Next
Return inRange
End Function

Resources