绑定到 Decimal 属性时,如何停止空 WPF 文本框上的红色边框?

How do I stop the red border on an empty WPF textbox when bound to a Decimal property?

提问人:Kev12853 提问时间:3/28/2023 更新时间:3/28/2023 访问量:183

问:

我有一个绑定到可为 null 的十进制属性的文本框。

<TextBox Text="{Binding DueRent}" Style="{x:Null}"  Width="150"/>
public decimal? DueRent { get => _dueRent; set => _dueRent = value; }

当我的 TextBox 首次显示时,它包含 Null,并且没有显示错误模板。如果我使它无效,比如输入“aa”或“space”,那么我会得到红色边框,太好了。如果我输入一个有效的数字,比如 23.7,边界就会消失,这又太好了。但是,如果我只是删除无效文本或有效数字,我会得到红色边框,这不是很好。我希望“空”文本框显示红色边框。该值不是必需的值,但显然,如果输入该值,则它需要有效。验证比只是一个有效的小数点要复杂一些,但在其他地方会处理。

当输入无效条目时,似乎不会调用 getter 或 setter,它只是出错。

如果我使用 Validation.Template

                <Setter Property="Validation.ErrorTemplate">
                    <Setter.Value>
                        <ControlTemplate>
                            <DockPanel>
                                <TextBlock DockPanel.Dock="Left" FontWeight="Bold" Foreground="Red">*</TextBlock>
                                <TextBlock DockPanel.Dock="Bottom" Foreground="Purple" Text="{Binding ErrorContent}" />
                                <Border BorderBrush="Red" BorderThickness="2">
                                    <AdornedElementPlaceholder />
                                </Border>
                            </DockPanel>
                        </ControlTemplate>with the 
                    </Setter.Value>
                </Setter>

然后显示的消息是“值 aa 无法转换”,这与“aa”不能转换为小数一样有意义,但是,如果我随后将另一个无效值放入框中并按 Tab 键离开,则错误消息不会更改,这表明它没有使用新的无效数据重新验证自己?!?

我尝试过 FallBackValue = 0 和 = x:Null。

我尝试了此处找到的 Binding.ValidationRules 如何让 TextBox 只接受 WPF 中的数字输入?

当值为“aa”时,它返回 IsValid=False 并返回正确的错误消息,当值为 '' 时返回 IsValid=True,但文本框保持无效,并显示新消息“Value '' cannot be converted”,它不是从 Binding.ValidationRules 获取的

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var validationResult = new ValidationResult(true, null);

        if (value != null )
        {
            if (!string.IsNullOrEmpty(value.ToString()))
            {
                var regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
                var parsingOk = !regex.IsMatch(value.ToString());
                if (!parsingOk)
                {
                    validationResult = new ValidationResult(false, "Illegal Characters, Please Enter Numeric Value");
                }
            }
        }

        return validationResult;
    }

当 TextBox 为空时,如何阻止 TextBox 进入错误状态?

谢谢。

WPF 验证 文本框

评论

0赞 Andy 3/28/2023
您最好只允许输入有效字符 imo。如果你在谷歌上搜索,你会发现代码允许你这样做。然后,用户键入“A”,文本框中不会显示任何内容。但是你处于这个位置,因为你认为这个属性是可为空的。你确定这是个好主意吗?
0赞 Kev12853 3/28/2023
安迪,感谢您的评论。不记得为什么它是可为 null 的。我会取消它,看看会发生什么。你能解释一下为什么它会导致这个问题吗?谢谢
0赞 Andy 3/29/2023
如果 empty 无效,则他们必须输入一个有效的数字。错误的工作方式是,当输入无效时会引发一个事件。有效数据传输时,将引发相同的事件。键入 aa 失败,并引发事件,指出存在错误。将其替换为有效数字意味着它会转移并再次引发事件,表示它现在有效。
0赞 Kev12853 3/29/2023
@Andy 知道了,谢谢。感谢您的帮助。凯文

答:

0赞 BionicCode 3/28/2023 #1

您不能绑定到非类型并期望其表现得特殊。它不是数字输入控件。由于属性的名称及其类型指示它是输入控件。
与非属性类型的绑定之所以有效,是因为 XAML 引擎使用类型转换器并尝试将值从正确的类型转换为正确的类型(在本例中)。由于存在 to 转换的默认转换器,因此如果字符串为数字,则不会出现转换错误。
但 still 的行为类似于文本输入字段。虽然空字符串是有效值,但默认情况下,它不能转换为数值。
TextBox.TextstringTextBoxTextstringstringstringdecimalstringdecimalTextBoxstring

您必须提供正确的转换,例如将空转换为 。或者,截获键盘输入以将空格替换为 。这需要一些额外的逻辑,例如抑制多个空格字符。string00

为抑制空字符串输入的单个用例附加转换器似乎更方便:

public class WhitespceToNumericValueConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    => value;

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    => value is string input && string.IsNullOrWhiteSpace(input) 
      ? 0 
      : value;
}
<Window.Resources>
  <WhitespceToNumericValueConverter x:Key="WhitespceToNumericValueConverter" />
</Window.Resources>

<TextBox Text="{Binding DueRent, Converter={StaticResoucre WhitespceToNumericValueConverter}}" />

评论

0赞 Kev12853 3/28/2023
仿生代码。非常感谢您的回复,是的,我很欣赏您关于它是一个文本框的评论,我希望绑定验证会拦截 xaml 引擎,但显然不是。转换器将解决这个问题,但理想情况下,我希望文本框为空。当值为 null 时,为什么第一次显示窗体时不会出错?如果转换器返回 Null 而不是 0,那会起作用吗?非常感谢
0赞 BionicCode 3/28/2023
验证不会更改值或阻止分配该值。它只是告诉绑定引擎该值在数据验证方面是否有效。绑定引擎只对是否显示视觉错误反馈感兴趣。你不能强迫价值。另一方面,转换器可以完全控制分配给源和目标的实际值。如果要有一个空的输入字段,则必须将 Text 属性绑定到属性。string
0赞 BionicCode 3/28/2023
然后,如果需要,在此属性中将值分配给数值类型化属性。在你的例子中,你会用它来检查字符串是否有效(如果 是有效数字,它将返回)。 并公开相同的方法。此外,使用此方法将 转换为数值数据类型。使用此方法代替正则表达式,因为正则表达式会变慢且不适合此用例。decimal.TryParsedecimaltruestringintdoubleTryParsestring
0赞 BionicCode 3/28/2023
如果对 TextBox 的输入或行为有更多限制,则建议扩展 TextBox 类以将所有相关逻辑移动到该类。它将从此 UI 相关逻辑中保持数据源干净。无论约束数量如何,扩展 TextBox(例如)都是干净的方法。如果您有时间,请创建一个 .你很可能有一天会再次需要它。NumericTextBoxNumericTextBox
0赞 Kev12853 3/29/2023
感谢您的输入。我会花一些时间仔细阅读您的解释和建议,看看我能学到什么。感谢您的帮助。凯文