IDataErrorInfo 接口如何工作?

发布于 2024-09-06 13:10:52 字数 1100 浏览 4 评论 0原文

我目前正在研究我的 WPF 应用程序的验证,并看到提到了 IDataErrorInfo。然而,关于如何使用它的指南很少,更糟糕的是,没有人解释它是如何工作的。

MSND.com 网站上给出了以下内容: MSDN

public class Person : IDataErrorInfo
{
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    public string Error
    {
        get
        {
            return null;
        }
    }

    public string this[string name]
    {
        get
        {
            string result = null;
            if (name == "Age")
            {
                if (this.age < 0 || this.age > 150)
                {
                    result = "Age must not be less than 0 or greater than 150.";
                }
            }
            return result;
        }
    }
}

我看到了什么在这里发生,但我不知道它对我的数据到底有什么影响。

这两个属性什么时候使用?假设有人将 Age 设置为 400:调用该属性的 setter。错误会阻止它被设置吗?如果不是,它只是警告号码不正确,那么如何阻止某人按原样保存信息呢?没有 IsValid() 方法可以检查,是吗?

很想知道幕后发生了什么。

I'm currently looking into validation for my WPF app and seen the mention of IDataErrorInfo. However there are few guides to how to use it and worse there are none who explain how it works.

On MSND.com site this is given:
MSDN

public class Person : IDataErrorInfo
{
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    public string Error
    {
        get
        {
            return null;
        }
    }

    public string this[string name]
    {
        get
        {
            string result = null;
            if (name == "Age")
            {
                if (this.age < 0 || this.age > 150)
                {
                    result = "Age must not be less than 0 or greater than 150.";
                }
            }
            return result;
        }
    }
}

I see what's going on here but I have no idea what it really does to my data.

When are those 2 properties used? Let's say someone sets Age as 400: the setter on the property is called. Will the error thingy stop it from being set? If not and it just warns that the number is incorrect, what's to stop someone from saving the info as is? There is no IsValid() method to check, is there?

Would love to know what happens behind the curtains.

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

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

发布评论

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

评论(2

梦回梦里 2024-09-13 13:10:52

Error 属性通常不被使用,但您必须定义它才能实现该接口。
正如 decyclone 所说,验证不会阻止属性设置错误的值,但您可以将属性设置为默认值。
让我向您展示我是如何使用它的。我有几个 TextBoxes,我必须验证它们所具有的值。我不想在调用集合时显示带有错误的 MessageBox,而是想采用“webly”方法:当设置无效值时,我希望 TextBox 的边框和背景为红色以及 TextBox 的工具提示来显示它收到的错误。

这是我的 TextBox 的 xaml:

<converters:ValidationConverter x:Key="validationConverter"/>
<Style x:Key="TestStepTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="Validation.HasError" Value="true">
                        <Setter Property="ToolTip"
                                Value="{Binding RelativeSource={RelativeSource Self}, 
                                Converter={StaticResource validationConverter}, Path=(Validation.Errors)}"/>
                        <Setter Property="Background" Value="#33FF342D"/>
                        <Setter Property="BorderBrush" Value="#AAFF342D"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<TextBox Name="txtRunAfter" Text="{Binding RunAfter, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource TestStepTextBox}"/>
<TextBox Name="txtStopAfter" Text="{Binding StopAfter, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource TestStepTextBox}"/>

关于转换器的非常重要的说明。当我输入无效值然后设置一个好的值时,出现异常。不知何故,可能与 UpdateSourceTrigger=PropertyChanged 有关,有一段时间 HasError 属性为 true,但没有设置错误(请参阅 链接)。因此,这里是转换器的代码:

public class ValidationConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ReadOnlyObservableCollection<ValidationError> errors = value as ReadOnlyObservableCollection<ValidationError>;
        if (errors == null) return value;
        if (errors.Count > 0)
        {
            return errors[0].ErrorContent;
        }
        return "";
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException("This method should never be called");
    }
}

为了防止将无效值保存到我的模型层,我使用相同的方法来检查是否应该将数据提交到模型。如果该值无效,我只是设置该属性,而不调用模型中的一组属性。检查代码:

private int _runAfter = 0;
public int RunAfter
{
    get
    {
        return _runAfter;
    }

    set
    {
        if (_runAfter != value)
        {
            _runAfter = value;
            OnPropertyChanged("RunAfter");

            if (validateRunAfter() == null)
                setRunAfter(); //sets the property value to the model layer
        }
    }
}

string IDataErrorInfo.this[string columnName]
{
    get
    {
        string message = null;
        if (columnName == "RunAfter")
            message = validateRunAfter();
        //...
        return message;
    }
}

private string validateRunAfter()
{
    if (value >= _order)
        return "Run After value must be less than its Step Order (#) value.";

    return null;
}

The Error property is not usually used, but you have to define it in order to implement the interface.
As decyclone said, Validation won't stop the property from being set with the wrong value, but you could set the property to a default value.
Let me show you how I'm using it. I have a couple of TextBoxes that I have to validate the values they have. Instead of showing a MessageBox with the error when the set is called, I want to take a 'webly' approach: I want the border and the background of the TextBox to be red when an invalid value is setted and the tooltip of the TextBox to show the error it got.

This is my xaml for TextBox:

<converters:ValidationConverter x:Key="validationConverter"/>
<Style x:Key="TestStepTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="Validation.HasError" Value="true">
                        <Setter Property="ToolTip"
                                Value="{Binding RelativeSource={RelativeSource Self}, 
                                Converter={StaticResource validationConverter}, Path=(Validation.Errors)}"/>
                        <Setter Property="Background" Value="#33FF342D"/>
                        <Setter Property="BorderBrush" Value="#AAFF342D"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<TextBox Name="txtRunAfter" Text="{Binding RunAfter, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource TestStepTextBox}"/>
<TextBox Name="txtStopAfter" Text="{Binding StopAfter, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource TestStepTextBox}"/>

A very important note about the converter. I was getting an exception when I entered an invalid value and then I set a good value. Somehow, maybe related to having UpdateSourceTrigger=PropertyChanged, there was a time when the HasError property was true but there were no error set (see link). So here is the code for the Converter:

public class ValidationConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ReadOnlyObservableCollection<ValidationError> errors = value as ReadOnlyObservableCollection<ValidationError>;
        if (errors == null) return value;
        if (errors.Count > 0)
        {
            return errors[0].ErrorContent;
        }
        return "";
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException("This method should never be called");
    }
}

To prevent the invaled value from being saved to my model layer I'm using the same method to check if I should commit the data to the model. If the value is invalid I just set the property and don't call a set of the property in the model. Check the code:

private int _runAfter = 0;
public int RunAfter
{
    get
    {
        return _runAfter;
    }

    set
    {
        if (_runAfter != value)
        {
            _runAfter = value;
            OnPropertyChanged("RunAfter");

            if (validateRunAfter() == null)
                setRunAfter(); //sets the property value to the model layer
        }
    }
}

string IDataErrorInfo.this[string columnName]
{
    get
    {
        string message = null;
        if (columnName == "RunAfter")
            message = validateRunAfter();
        //...
        return message;
    }
}

private string validateRunAfter()
{
    if (value >= _order)
        return "Run After value must be less than its Step Order (#) value.";

    return null;
}
吖咩 2024-09-13 13:10:52

据我所知,IDataErrorInfo 仅用于 UI 目的。它的作用是提供一种将错误消息绑定到 WPF UI 的简单方法。由于 WPF UI 会像 INotifyPropertyChanged 一样“识别”实现 IDataErrorInfo 的对象,因此您无需编写额外的代码来显示错误消息在用户界面中。

另一件事是,它不会阻止被设置错误的值。它只会告诉 WPF UI(当 WPF UI 调用提供属性名称的索引器时)特定属性中的值无效。

What I know of IDataErrorInfo is it is used for UI purposes only. What it does is provide an easy way to bind the error message(s) to the WPF UI. Since WPF UI "identifies" the objects that implement IDataErrorInfo just like INotifyPropertyChanged, you don't have to write extra code to show the error messages in the UI.

One more thing, it will not stop from being set the wrong value. It will just tell the WPF UI (when WPF UI calls the indexer supplying property name) that the value in a specific property is not valid.

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