当属性抛出错误时,如何将其设置为空值?

发布于 2024-12-29 04:30:26 字数 651 浏览 3 评论 0原文

WPF 中的绑定非常强大。假设我们有一个 Number 属性(可为 null int)并且绑定到一个文本框。

我意识到当它抛出错误时,该属性具有最后的正确值。

我的意思是这些过程:

TEXTBOX: ""     PROPERTY: null
TEXTBOX: "2"    PROPERTY: 2
TEXTBOX: "2b"   PROPERTY: 2   <-- here is the problem, should be null instead 2(by the error)

有没有一种方法可以让绑定在产生错误时设置空值?

有些人告诉我我需要实现 IDataErrorInfo,但我想该接口是为了验证业务规则。所以我不喜欢使用它。

更新:

    <TextBox Text="{Binding Number, UpdateSourceTrigger=PropertyChanged,
        ValidatesOnExceptions=True, ValidatesOnDataErrors=True,
        NotifyOnValidationError=True, TargetNullValue={x:Static sys:String.Empty}}"

Binding is so powerful in WPF. Supposed that we have a Number property (nullable int) and is bound to a textbox.

I realized when it throws an error, the property has the last correct value.

I mean these are the processes:

TEXTBOX: ""     PROPERTY: null
TEXTBOX: "2"    PROPERTY: 2
TEXTBOX: "2b"   PROPERTY: 2   <-- here is the problem, should be null instead 2(by the error)

Is there a way which the binding set a null value when it produce an error?

Some persons told me I need to implement IDataErrorInfo, but I guess that interface is to validate business rules. So I wouldn't prefer user it.

UPDATE:

    <TextBox Text="{Binding Number, UpdateSourceTrigger=PropertyChanged,
        ValidatesOnExceptions=True, ValidatesOnDataErrors=True,
        NotifyOnValidationError=True, TargetNullValue={x:Static sys:String.Empty}}"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼眸里的那抹悲凉 2025-01-05 04:30:26

您正在使用 UpdateSourceTrigger=PropertyChanged,这意味着只要用户按下某个键,它就会将数据存储在您的数据上下文中。

例如,用户输入 2,然后输入您的属性等于“2”。用户输入 b,它将尝试用 "2b" 替换 "2",但失败,因此 " 的原始属性2" 仍然存在。

删除UpdateSourceTrigger,它将恢复为默认的LostFocus,这意味着它只会在 TextBox 失去焦点时更新属性。

当产生错误时,您可以将该属性设置为 null,但我不建议这样做,因为如果用户不小心按错了键,TextBox 将被清除。

附带说明一下,请使用 IDataErrorInfo 进行所有验证,而不仅仅是业务规则验证。 WPF 就是为了与它一起工作而构建的。我的模型使用它来验证其数据的长度、类型等是否正确,我的 ViewModel 使用它来验证是否遵循业务规则

编辑

我的替代建议是绑定到字符串值,而不是数字字段。这样,当值发生变化时,您可以尝试将其转换为 Int,如果无法转换则返回错误。

public class SomeObject : IDataErrorInfo
{
    public string SomeString { get; set; }
    public Int32? SomeNumber { get; set; }

    #region IDataErrorInfo Members

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "SomeString")
            {
                int i;
                if (int.TryParse(SomeString, i))
                {
                    SomeNumber = i;
                }
                else
                {
                    SomeNumber = null;
                    return "Value is not a valid number";
                }
            }
            return null;
        }
    }

    #endregion
}

You are using UpdateSourceTrigger=PropertyChanged, which means that anytime the user hits a key, it is storing the data in your data context

For example, user types 2, then your property is equal to "2". User types b and it will attempt to replace "2" with "2b", which fails, so the original property of "2" remains.

Remove the UpdateSourceTrigger and it will revert to the default of LostFocus, which means it will only update the property when the TextBox loses focus.

You could set the property to null when an error is produced, but I would not recommend doing that because then if a user accidently hits the wrong key, the TextBox would get cleared.

As a side note, use IDataErrorInfo for all validation, not just business rule validation. WPF is built to work with it. My Models use it to verify their data is the correct length, type, etc, and my ViewModels use it to verify that business rules are being followed

Edit

The alternative suggestion I would have would be to bind to a string value, not a number field. This way when the value changes, you can try and cast it to your Int and return an error if it can't be cast.

public class SomeObject : IDataErrorInfo
{
    public string SomeString { get; set; }
    public Int32? SomeNumber { get; set; }

    #region IDataErrorInfo Members

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "SomeString")
            {
                int i;
                if (int.TryParse(SomeString, i))
                {
                    SomeNumber = i;
                }
                else
                {
                    SomeNumber = null;
                    return "Value is not a valid number";
                }
            }
            return null;
        }
    }

    #endregion
}
幸福还没到 2025-01-05 04:30:26

我认为获得该行为的最简单方法是使用 IValueConverterstring 转换为 int?

public class NullableIntConverter : IValueConverter
{
    public static NullableIntConverter Instance = new NullableIntConverter();
    public void ConvertBack(object value, ...)
    {
        int intValue = 0;
        if (int.TryParse((string)value, out intValue))
            return intValue;

        return null;
    }

    public void Convert(object value, ...)
    {
        return value.ToString();
    }
}

然后您可以在您的绑定如下(其中 local 映射到您的转换器命名空间):

<TextBox Text="{Binding Number, Converter="{x:Static local:NullableIntConverter.Instance}" ... />

I think that the simplest way to get that behaviour is to use an IValueConverter to convert from string to int?:

public class NullableIntConverter : IValueConverter
{
    public static NullableIntConverter Instance = new NullableIntConverter();
    public void ConvertBack(object value, ...)
    {
        int intValue = 0;
        if (int.TryParse((string)value, out intValue))
            return intValue;

        return null;
    }

    public void Convert(object value, ...)
    {
        return value.ToString();
    }
}

Then you can specify this in your binding as below (where local is mapped to your converter namespace):

<TextBox Text="{Binding Number, Converter="{x:Static local:NullableIntConverter.Instance}" ... />
狠疯拽 2025-01-05 04:30:26

它变得更加强大。您可能应该通过接口/绑定本身进行验证 - WPF 对此有内置支持,其示例可以在 MSDN 上的数据绑定概述

实现此操作的示例如下:

<...>
  <Binding.ValidationRules>
    <ExceptionValidationRule />
  </Binding.ValidationRules>
</...>

链接的文档涵盖了有关绑定主题的大量内容,因此这里是相关部分“数据验证”的摘录:

ValidationRule 对象检查属性的值是否为
有效。

ExceptionValidationRule 检查在执行期间抛出的异常
更新绑定源属性。在前面的例子中,
StartPrice 是整数类型。当用户输入一个值时
无法转换为整数,抛出异常,导致
绑定被标记为无效。设置的替代语法
ExceptionValidationRule 显式地设置
您的 Binding 上的 ValidatesOnExceptions 属性设置为 true 或
MultiBinding 对象。

It gets more powerful yet. You probably ought to go the route of validation via the interface/binding itself - WPF has built-in support for this, examples of which can be found in the Data Binding Overview over at MSDN.

An example of implementing this could go as follows:

<...>
  <Binding.ValidationRules>
    <ExceptionValidationRule />
  </Binding.ValidationRules>
</...>

The linked documentation covers quite a bit on the topic of binding, so here is an excerpt from the relevant section 'Data Validation':

A ValidationRule object checks whether the value of a property is
valid.

A ExceptionValidationRule checks for exceptions thrown during the
update of the binding source property. In the previous example,
StartPrice is of type integer. When the user enters a value that
cannot be converted to an integer, an exception is thrown, causing the
binding to be marked as invalid. An alternative syntax to setting the
ExceptionValidationRule explicitly is to set the
ValidatesOnExceptions property to true on your Binding or
MultiBinding object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文