You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:55:08