Decimal.TryParse is failing on TextBox.Leave and TextBox.LostFocus
This has got to be one of the most frustratingly stupid bugs I have ever encountered, and I just want to see if anybody else has run into this before.
Here's the deal. I have a TextBox in a Windows Forms application in VB 2008 (.NET 3.5) where a user can key an estimate amount. I am allowing them to key dollars and cents, and I want to round to the nearest dollar. The original code had the rounding down when the data was written back to a table, and that worked fine - I have this code in a "Save" routine that fires when the user moves to a different screen or record:
Dim est As Decimal : Decimal.TryParse(txtEstimateAmount.Text.Trim, est)
Dim estimatedAmount As Integer = Math.Round(est)
I decided that it might be nice to actually do the rounding as soon as they leave the field instead, so they're not surprised when they reload the screen and find that 1822.60 is now 1823. So I took the exact same code and added it to the TextBox.Leave event handler. And the weirdest thing happened: instead of the variable est being populated with 1822.60 after the parse, it gets set to -1! What the...?
Debugging the handler shows that the val开发者_如何学JAVAue goes into the parser correctly, and if I do the parsing manually via the Immediate window, it parses correctly, but when I let the code do it, it invariably gets set to -1. What's even weirder is that any number gets parsed as -1, not just decimals, and any non-number gets parsed as 0 (which is correct).
Has anybody else ever run into this before? I tried moving the code to the TextBox.LostFocus event instead, but with the same results. I have no idea what in the heck is going on, and obviously there are workarounds galore for this, but it just makes no sense whatsoever.
EDIT: Here's the full event handler (current behavior for which is to put -1 in the TextBox):
Private Sub txtEstimateAmount_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtEstimateAmount.Leave
' Take any dollars-and-cents amount and round to the nearest dollar
Dim est As Decimal
est = Decimal.TryParse(txtEstimateAmount.Text.Trim, est)
txtEstimateAmount.Text = If(est <> 0, Math.Round(est).ToString(), String.Empty)
End Sub
First off, you really need to do this with a Validating event handler so that you can catch junk and avoid ignoring the return value of TryParse. Like this:
Private Sub TextBox1_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
Dim est As Decimal
If TextBox1.Text.Length = 0 then Exit Sub '' optional
If Not Decimal.TryParse(TextBox1.Text.Trim, est) Then
e.Cancel = True
TextBox1.SelectAll()
Else
TextBox1.Text = est.ToString("N0")
End If
End Sub
Explaining -1 is difficult. TryParse normally writes 0 if it cannot parse the text. Watch out for changing the UI thread's CurrentCulture property. And any changes made to the format settings in Control Panel + Region and Language applet.
I don't think the code you've posted is the code you're running. What is happening is:
Dim est As Decimal = Decimal.TryParse(txtEstimateAmount.Text.Trim, est)
Dim estimatedAmount As Integer = Math.Round(est)
I would do a clean and a rebuild or try rewriting it in a different format, maybe with a boolean to get the result of the tryparse.
EDIT now that I've seen your actual code. You are indeed putting the true/false from the tryparse result into the est decimal. Delete the est=. Est gets loaded because it is passed by reference into tryparse.
精彩评论