自定义TextBox货币控件设计时触发TextChanged引发异常求助
问题解答
1. 设计时触发txt_TextChanged是否正常?
这个现象是正常的。当你把自定义控件拖到设计界面时,Visual Studio设计器会实例化控件并执行构造函数,而构造函数里设置了Me.Text = "0.00 US",这会直接触发TextChanged事件,所以该事件会在设计阶段被执行。
2. 解决FormatException错误及控件正常工作的修复方案
错误根源是设计阶段执行TextChanged时,处理后的字符串为空,导致CDbl转换失败。另外原代码存在逻辑漏洞,以下是完整修复后的代码:
Imports System.Globalization Public Class uc_txt_cur Inherits TextBox Property xCurrency As String = "US" Property xDecimal As Integer = 2 ' 标记当前是否处于设计模式 Private isDesignMode As Boolean Property xValue As String Property xIntegerValue As Integer Property xDoubleValue As Double Private Sub InitializeComponent() Me.SuspendLayout() Me.ResumeLayout(False) End Sub Sub New() ' 判断当前模式 isDesignMode = LicenseManager.UsageMode = LicenseUsageMode.Designtime Me.TextAlign = HorizontalAlignment.Right ' 设计模式下仅显示基础文本,跳过格式化逻辑 If isDesignMode Then Me.Text = "0.00 US" Else ResetToDefault() End If End Sub ' 重置控件为默认状态 Private Sub ResetToDefault() Me.Text = $"0.00 {xCurrency}" UpdateValueProperties(0) End Sub ' 同步更新数值属性 Private Sub UpdateValueProperties(value As Double) xDoubleValue = value xIntegerValue = CInt(Math.Round(value)) xValue = value.ToString($"N{xDecimal}") End Sub Private Sub txt_TextChanged(sender As Object, e As EventArgs) Handles Me.TextChanged ' 设计模式下直接跳过,避免报错 If isDesignMode Then Return Try ' 保存当前光标位置 Dim cursorPosition = Me.SelectionStart ' 过滤输入:仅保留数字和单个小数点 Dim rawInput As String = String.Join("", Me.Text.Where(Function(c) Char.IsDigit(c) OrElse c = "."c)) Dim dotIndex = rawInput.IndexOf(".") If dotIndex > -1 Then rawInput = rawInput.Substring(0, dotIndex + 1) & rawInput.Substring(dotIndex + 1).Replace(".", "") End If ' 处理空输入或纯小数点的情况 If String.IsNullOrEmpty(rawInput) OrElse rawInput = "." Then Me.Text = $"0.00 {xCurrency}" UpdateValueProperties(0) Else Dim numericValue As Double = CDbl(rawInput) ' 限制小数位数 numericValue = Math.Round(numericValue, xDecimal) Me.Text = numericValue.ToString($"N{xDecimal}") & $" {xCurrency}" UpdateValueProperties(numericValue) End If ' 恢复光标到合理位置(货币符号前) Me.SelectionStart = Math.Min(cursorPosition, Me.Text.Length - xCurrency.Length - 1) Catch ex As FormatException ResetToDefault() End Try End Sub Private Sub txt_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress ' 设计模式下允许所有输入,方便设计调整 If isDesignMode Then Return If Char.IsDigit(e.KeyChar) OrElse Char.IsControl(e.KeyChar) Then ' 允许数字和控制字符(退格、删除等) ElseIf e.KeyChar = "."c AndAlso Not Me.Text.Contains(".") Then ' 允许单个小数点 Else ' 屏蔽其他输入 e.Handled = True End If End Sub End Class
关键修复点说明:
- 设计模式隔离:通过
LicenseManager.UsageMode区分设计/运行模式,设计阶段跳过格式化逻辑,避免构造函数触发错误。 - 严谨的输入过滤:只保留数字和单个小数点,避免空字符串或无效格式传入转换函数。
- 光标位置维护:格式化后恢复合理光标位置,提升输入体验。
- 数值属性同步:统一更新关联数值属性,确保数据一致性。
- 异常兜底:出错时重置控件到默认状态,避免界面异常。
内容的提问来源于stack exchange,提问作者Samir Ibrahim
相关产品推荐
相关产品推荐

