How to fix System.FormatException: 'Input string was not in a correct format' - vb.net

I am trying to change Font Family in VB.NET for a RichTextBox
I have tried searching through google and even specific sites for just code problems. Nothing works.
These are the codes for FontFamily changing (it is a tool strip combo button)
Private Sub TscFontFamily_TextChanged(sender As Object, e As EventArgs) Handles tscFontFamily.TextChanged
rtbContent.SelectionFont = New Font(Convert.ToString(tscFontFamily.Text), Convert.ToInt32(tscFontSize.Text))
End Sub
And the FontSize (also a tool strip combo button)
Private Sub tscFontSize_TextChanged(sender As Object, e As EventArgs) Handles tscFontSize.TextChanged
Dim newSize As Single = Convert.ToSingle(tscFontSize.Text)
rtbContent.SelectionFont = New Font(rtbContent.SelectionFont.FontFamily, newSize)
End Sub
I expect this to work since it makes sense, right? But it says "input string was not in correct format" and if i remove the Convert.ToString and other convert code, it says something like "Conversion from string "" to type 'Single' is not valid.".
Also to mentiion, is the fact that i have actually tried Convert.ToString and Convert.ToDouble and basically everything for BOTH.

There is no need to call ToString on tscFontFamily.Text because the Text property of a TextBox returns a String; you're essentially saying return a String value from this String value.
Convert.ToInt32 is a quick and dirty was of converting String values to Int32 (aka integer) values. If you're relying on input from a user then you should almost always use Int32.TryParse instead. This method returns a Boolean value based on if the conversion of the input is successful and then the second parameter passed is a reference variable so if the result of the method is True then the second parameter contains the converted value. However, it looks like you're wanting a Single value in which case you'd actually use Single.TryParse.
Here would be an example applying the changes to your code:
Private Sub tscFontSize_TextChanged(sender As Object, e As EventArgs) Handles tscFontSize.TextChanged
Dim newSize As Single
If Single.TryParse(tscFontSize.Text, newSize) Then
rtbContent.SelectionFont = New Font(rtbContent.SelectionFont.FontFamily, newSize)
End If
End Sub

Related

How to pass a value to DGV Cell when its formatted to C2 format

I'm struggling find a specific answer to this question, therefore asking it myself...
I have a DataGridView with columns which has the following formatting applied to it:
DGV.Columns(3).DefaultCellStyle.Format = "C2"
On the form there is a text box in which the user enters a number and that value is then entered in one of the cells in DGV:
For Each dr As DataGridViewRow In DGV.Rows
dr.Cells("ColumnHeader").Value = TextBox.Text
Next
Before the above code is executed, this event occurs on the TextBox to format its value:
Private Sub TextBox_Leave(sender As Object, e As EventArgs) Handles TextBox.Leave
TextBox.Text = FormatCurrency(TextBox.Text)
End Sub
The text within the TextBox is displaying correctly as a currency, but when the code to put that into a cell in the DGV executes it fails saying the value is in incorrect format.
Is DGV.Columns(3).DefaultCellStyle.Format = "C2" different format to FormatCurrency(TextBox.Text)?
That is all wrong. "C2" is a numeric format string, so it will only work on numbers. A String containing digit characters is not a number and a String containing currency text definitely isn't. You need to get the String from the TextBox, concert that to a number (probably Decimal for currency values) and then load that number into the grid. The grid converts that number, along with all the data, into text to display and will use your format string to do so:
dr.Cells("ColumnHeader").Value = CDec(TextBox.Text)
You would, presumably, already have validated the user input by this stage, so there's no possibility of CDec throwing an exception.
If the intent is to display the data formatted as currency in both the grid and the TextBox then you should get rid of your Leave event handler and handle the Validating and Validated events instead. The first will validate the input to ensure that it is numeric and the second will do the formatting:
Private Sub TextBox1_Validating(sender As Object, e As CancelEventArgs) Handles TextBox1.Validating
If Not Decimal.TryParse(TextBox1.Text, NumberStyles.Currency, Nothing, Nothing) Then
'Don't let the control lose focus when it contains invalid data.
e.Cancel = True
End If
End Sub
Private Sub TextBox1_Validated(sender As Object, e As EventArgs) Handles TextBox1.Validated
TextBox1.Text = Decimal.Parse(TextBox1.Text, NumberStyles.Currency).ToString("C2")
End Sub
That code will allow the user to enter the currency symbol or not, but it will ensure that the format is currency with two decimal places once it loses focus. You would then need to allow for the formatting when copying to the grid:
dr.Cells("ColumnHeader").Value = Decimal.Parse(TextBox1.Text, NumberStyles.Currency)

User enters letter then button computes position from a string using VB

I am using indexOf but I cannot figure out where I made a mistake as the output gives a -1.
I realise I can copy the whole statement paragraph into the last line of the output but I was hoping it could pull it straight from the label.
Public Class Form1
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
Dim statement As String
Dim letter As String
statement = CStr(lblStatement.Text)
letter = CStr(txtLetter.Text)
txtOutput.Text = CStr(lblStatement.Text).IndexOf("letter")
'txtOutput.Text = letter.ToUpper & " first occurs in position " & statement.IndexOf(statement) & "."
End Sub
End Class
Here is a picture of the form:
Update: Thanks to #ADyson and #Slugsie for taking the time to respond to my call for help. As #Slugsie noted it was indeed down to the lower case in my screenshot. I am now researching how to make it work without being case-sensitive.
Final code
Public Class Form1
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
txtOutput.Text = lblStatement.Text.IndexOf((txtLetter.Text).ToUpper)
End Sub
End Class
.IndexOf("letter")
is looking for the literal text letter within the data the user enters in the text. in VB.NET (and most other programming languages), anything enclosed within quote marks is treated as a fixed string of text, to be interpreted as-is rather than processed or treated as program code.
To make it look for the contents of the letter variable instead (which looks like what you were intending) simply remove the quote marks:
.IndexOf(letter)
As an aside, your whole code could be much reduced - primarily the use of CStr is unnecessary, because the Text properties of the textbox and label already return a string - meaning you don't need to use CStr convert it - and also because you're not making use of all the variables you declared either.
You could re-write your whole sample much more succinctly as:
Public Class Form1
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
txtOutput.Text = lblStatement.Text.IndexOf(txtLetter.Text)
End Sub
End Class

VB 'Option Strict' issue with conversion from double to long

I just started using VB and had to switch 'Option Strict' to on. I got this error in my code saying "Option Strict On disallows implicit conversions from 'double to long.'" I know what it means, but my friend and I can not seem to resolve the issue.
Error: "Option Strict disallows implicit conversions from 'Double' to 'Long' for both value1 and value 2 on line 24. (Private Sub btnIntDiv_Click)
Here is the code:
Public Class frmMathCalculator
Dim value1 As Double
Dim value2 As Double
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
value1 = Integer.Parse(txtValue1.Text)
value2 = Integer.Parse(txtValue2.Text)
Dim addResult As Double = value1 + value2
lstAnswer.Items.Add(addResult)
End Sub
Private Sub btnSubtract_Click(sender As Object, e As EventArgs) Handles btnSubtract.Click
Dim subtractResults As Double = value1 - value2
lstAnswer.Items.Add(subtractResults)
End Sub
Private Sub btnMultiply_Click(sender As Object, e As EventArgs) Handles btnMultiply.Click
Dim multiplyResults As Double = value1 * value2
lstAnswer.Items.Add(multiplyResults)
End Sub
Private Sub btnLongDiv_Click(sender As Object, e As EventArgs) Handles btnLongDiv.Click
Dim divideResults As Double = value1 / value2
lstAnswer.Items.Add(divideResults)
End Sub
Private Sub btnIntDiv_Click(sender As Object, e As EventArgs) Handles btnIntDiv.Click
Dim intDivResults As Double = value1 \ value2
lstAnswer.Items.Add(intDivResults)
End Sub
Private Sub btnMod_Click(sender As Object, e As EventArgs) Handles btnMod.Click
Dim modResults As Double = value1 Mod value2
lstAnswer.Items.Add(modResults)
End Sub
Private Sub btnExponent_Click(sender As Object, e As EventArgs) Handles btnExponent.Click
Dim expResults = value1 ^ value2
lstAnswer.Items.Add(expResults)
End Sub
End Class
Consider:
Public Class frmMathCalculator
Private value1 As Double 'we typically specify access levels like public or private for variables declared inside a class
Private value2 As Double
'We need to do this often, so rather than repeat the parsing in every
'Button click handler we create a sub we can call
Private Sub ParseUserInput()
'TODO: switch these to TryParse and provide user feedback if input is bad
'TODO: make this sub a function that returns a Boolean and return false if input is bad
value1 = Double.Parse(txtValue1.Text) 'value1 is a double, so use double.parse not int.parse
value2 = Double.Parse(txtValue2.Text)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
ParseUserInput() 'set our value variables
'VB will be able to work out that double + double is double so can skip the "As Double" bit
Dim addResult = value1 + value2
'List.Items.Add takes an object, and the list will simply call ToString on it when it wants
' to display it. For a double this is fine unless we want to format it - more on this later
lstAnswer.Items.Add(addResult)
End Sub
I haven't done all of them, but the pattern is repeatable..
This is ultimately an exercise in precision and knowing about datatypes. Functions take variables that are a certain type and emit data that has a type, possibly different. You need to keep consistency and generally be aware all the time what types of data are being put where
Double.Parse takes in a string, returns a double. Double+Double results in a double. ListBox.Items.Add takes in an object (returns nothing, but some collection add methods return something that you might capture and use) so you can put anything you like in but it's important to appreciate that to display it it has to be a string. To achieve this, if you didn't tell List to display the contents of a particular property of the item, then list will just blindly call ToString on the object you put in. For a double this is fine- it just takes the 1.234 double and makes it a string "1.234" which looks the same. If however you have created some custom class like Person, but you haven't provided a specialized variation of ToString that eg returns first name and last name, then all you'll see in your list is "MyNamespace.Person" over and over again. This is because by default ToString just returns the name of the kind of object.
Suppose in this case we wanted to format our doubles to 3dp all the time.. instead of putting the double in the list and having the list do the ToString, we could format a string and put it in: list.Items.Add(aDouble.ToString("0.000"))
So, which to use and why? If you're just using this list to hold the results, then format a string. You could even put the whole sum in: list.Items.Add($"{value1} + {value2} = {result:0.000} (to 3dp)")
If you're going to get these numbers back out of the list and do something with them later, keep them as doubles
If you want to get them out later and also have a customized presentation of them you need to add them as their own custom object that knows the value but can present a customized representation when asked. That's probably a bit advanced for now
With option strict off VB is very(overly) forgiving; if you try and put a string into something that takes a double, it'll try and convert the string to double for you. That's great, perhaps, but it doesn't encourage a strict mindset in the programmer - and eventually it goes wrong. Being mindful about the ins and outs and their types, and being explicit, is a great way to avoid subtle bugs in the future

Find and Replace using another form

I have my frmMainwhich has RichTextBox1 and I have a button btnfind&Replacewhich whose click event pops out another minute form frmFindandReplace which has two textboxes: TextBoxSearch and TextBoxReplace with two buttons: replaceButton and findButton. I cannot seem to get my code for instances of finding a word in textbox and an instance of replacing it. Here is my code:
Public Class frmFindandReplace
Dim txtClientArea As RichTextBox
Private Sub TextBoxSearch_TextChanged(sender As Object, e As EventArgs) Handles TextBoxSearch.TextChanged
End Sub
Private Sub frmFindandReplace_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub replaceButton_Click(sender As Object, e As EventArgs) Handles replaceButton.Click
End Sub
Protected Friend Sub findButton_Click(sender As Object, e As EventArgs) Handles findButton.Click
Dim a As String
Dim b As String
a = TextBoxSearch.Text
b = InStr(StartPosition, a, txtClientArea)
If b Then txtClientArea.Focus()
txtClientArea.SelectionStart = b - 1
txtClientArea.SelectionLength = Len(a)
txtClientArea.ScrollToCaret()
End Sub
The findButton code doesnot even work. Throws an error!
Error 3: Overload resolution failed because no accessible 'InStr' can be called with these arguments:
'Public Function InStr(Start As Integer, String1 As String, String2 As String, [Compare As Microsoft.VisualBasic.CompareMethod = Microsoft.VisualBasic.CompareMethod.Binary]) As Integer': Value of type 'System.Windows.Forms.TextBox' cannot be converted to 'String'.
'Public Function InStr(String1 As String, String2 As String, [Compare As Microsoft.VisualBasic.CompareMethod = Microsoft.VisualBasic.CompareMethod.Binary]) As Integer': Value of type 'System.Windows.Forms.RichTextBox' cannot be converted to 'Microsoft.VisualBasic.CompareMethod'. C:\Users\Joseph GodwinKE\Documents\Visual Studio 2013\Projects\simpleapp\frmFindandReplace.VB 25 13 Simple app
I know I have not done much but am new and all my efforts of searching a solution over the internet have failed! Thank you I hope someone will help me pls.
A few pointers:
InStr returns an integer.
Check the documentation as it'll show you have the search values the wrong way around.
Turn Option Explicit on to help find your issues.
This should work better.
Private Sub findButton_Click(sender As Object, e As EventArgs) Handles findButton.Click
Dim searchString As String
Dim findPos As Integer
Try
searchString = TextBoxSearch.Text
findPos = InStr(txtClientArea.Text, searchString)
If findPos > 0 Then txtClientArea.Focus()
txtClientArea.SelectionStart = findPos - 1
txtClientArea.SelectionLength = searchString.Length
txtClientArea.ScrollToCaret()
Catch ex As Exception
MessageBox.Show(String.Concat("An error occurred: ", ex.Message))
End Try
End Sub
If you want your code work you need to pass the reference to the RichTextBox present in the first form to the findandReplace form.
Otherwise you will not be able to work with that instance of the RichTextBox.
Usually, this means that when you create and open an instance of the findandReplace form you pass the reference to the RichTextBox to work with in the call to the constructor. Something like this
Dim fReplace As frmFindandReplace = New frmFindandReplace(Me.txtClientArea)
fReplace.Show()
Here the New call reaches the constructor of frmfindandReplace. This call is usually hidden by VB.NET but you could add it writing explicit code for it
Public Class frmFindandReplace
Dim txtClientArea As RichTextBox
Public Sub New (ByVal txt as RichTextBox)
txtClientArea = txt
End Sub
Now the global variable txtClientArea inside the findandReplace class is assigned to the existing reference of the RichTextBox present in the first form and you could happily work with it
Protected Friend Sub findButton_Click(sender As Object, e As EventArgs) Handles findButton.Click
Dim a As String
a = TextBoxSearch.Text
Dim position = txtClientArea.Find(a, 0, RichTextBoxFinds.MatchCase)
.....
End Sub
And please make yourself a favor and start using the more complete methods available from the NET Framework library and stop using the old fashioned VBA methods.
For example the RichTextBox has a method that does exactly what you are trying to do in code. Find, search the content of the textbox and if it founds a match it highlight the text and return the starting position of the text.
There is no replace builtin method but having the position and the length is really simple to implement your own replacing code.
You Have defined b as a string. Change it to an integer. Also Instr doesn't allow you to set a start position, just a string to search and the string to search for and optionally the type of search - Binary or Text.
Finally rather than type If b then, use If b>0 then rather than turning off Option Strict. It's always better to write code with Option Strict on as it makes you write better code and in the long run is easier to chase down errors

Checking for numeric value entered in text box in Visual Basic

I am working on a program for my Visual Basic class and have a quick question. One of the things we were encouraged to do was to check to make sure the quantity entered in a text box is actually a number. Our professor suggested using IsNumeric to perform this check, but I'm running into some trouble. I already had a good bit of the code written before he added this to the instructions, so not sure how to integrate this into the code I already have.
The main purpose of the program is to allow the user to add ingredients from one list box to the recipe list box, input a quantity for each selected ingredient in a text box, and calculate the total calories for the recipe. The way I have the code written now, IsNumeric is part of a nested if statement at the beginning of where I will start adding the selected ingredients to the recipe list box. I'm not sure if that's the correct place for it though.
Here is the code I have written so far.
Public Class Form1
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim i As Integer = lstIngredients.SelectedIndex
Dim Quantity As Double
Dim intCount As Integer = 0
If Trim(txtQuantity.Text = "") Then
Quantity = 1
Else
Quantity = Me.txtQuantity.Text
End If
If txtQuantity.Text Is IsNumeric() Then
If intCount < Quantity Then
lstRecipe.Items.Add(Quantity & " " & lstIngredients.Text)
intCount += 1
End If
Else
MessageBox.Show("The quantity entered is not numeric. Please add a numeric quantity.")
End If
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
lstRecipe.Items.Clear()
txtQuantity.Clear()
txtAnswer.Clear()
End Sub
Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
End Sub
End Class
Also, here is the error I receive when I attempt to run this program as it is written.
Error 1 Argument not specified for parameter 'Expression' of 'Public Function IsNumeric(Expression As Object) As Boolean'.
Any suggestions would be greatly appreciated.
A more correct way to do that is to use the TryParse method available in the Int32 or Double class
If Double.TryParse(txtQuantity.Text, Quantity) Then
If intCount < Quantity Then
lstRecipe.Items.Add(Quantity & " " & lstIngredients.Text)
intCount += 1
End If
Else
MessageBox.Show("The quantity entered is not numeric. Please add a numeric quantity.")
End If
And you could also remove the code that test for the empty textbox.
The TryParse method wants two parameters, the first one is the string that could be converted, the second parameter is the variable that receives the result of the conversion if it is possible. If the conversion cannot be executed the function returns false.
There are numerous reasons to prefer Double.TryParse instead of IsNumeric.
The first reason is that with TryParse you also get the result of the conversion while with IsNumeric you would have to do the conversion after the check.
The second reason is that you could give to IsNumeric whatever object you want (also a Button for example) and it accepts it. You would never discover this kind of errors at compile time. Instead, with TryParse, you could only pass a string as its first parameter.
You're just using the function incorrectly - you need to pass the string as a parameter.
If IsNumeric(txtQuantity.Text) Then
Use Regex.IsMatch:
Public Function isNumeric(input As String) As Boolean
Return Regex.IsMatch(input.Trim, "\A-{0,1}[0-9.]*\Z")
End Function
Yes, Double.Tryparse is the best answer to this question, but to save you time on coding and ensure that the value entered is always numeric, use the NumericDropdown control instead of the plain Text Box so that you are sure that inputted value is always numeric and save you time checking the inputted value since that control will not accept anything but numeric values only.
Use IsNumeric(txtQuantity.Text) if you have that method defined. Otherwise use Int32.TryParse() method. It will return true if the text passed in is a number.
Private Sub txbDwellTime_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txbDwellTime.KeyPress
numDecOnly(e)
End Sub
Public Sub numDecOnly(ByVal e As System.Windows.Forms.KeyPressEventArgs)
If (Asc(e.KeyChar) >= 48 And Asc(e.KeyChar) <= 57 Or Asc(e.KeyChar) = 46) Then
'good job do nothing we only allow positive Decimal numbers in this field
'Asc(e.KeyChar) 48 Through 57 i.e. 0 through 9 Or Asc(e.KeyChar) 46 (dot= .)
Else
e.Handled = True
MsgBox("Only Positive Decimal Numbers Allowed this field")
End If
End Sub