繁体   English   中英

是否可以创建通用的 ValidationRule 类?

[英]Is it possible to create generic ValidationRule classes?

我正在处理一个 .NET 4.0 项目,该项目处理特定数据类型范围的验证。 例如,32 位 int 应该仅介于Int32.MinValueInt32.MaxValue之间或应用程序定义的任何其他值。 我希望能够在自定义验证器上指定数据类型和范围,以便可以通过绑定直接从 xaml 调用它们: <CheckIfValueRangeValidator>

这就是我的想法,我不确定它是否有效,或者是否可以通过 xaml 完成。

class CheckIfValueInRangeValidator<T> : ValidationRule
{
    public T Max { get; set; }
    public T Min { get; set; }

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        // Implementation...
    }
}

我的不好,实际上你不能使用 x:TypeArguments 因为它会引发x:TypeArguments is not allowed in object elements for XAML version lower than 2009 ,它只对松散的 XAML 文件或根元素有效(在我的例子中是窗口)......

http://msdn.microsoft.com/en-us/library/ms750476.aspx

但作为一种解决方法,您可以使用以下模式:

    <TextBox x:Name="textBox1">
        <Binding Path="MyValue"
                     Source="{StaticResource MyObject}"
                     UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <wpfApplication6:MyValidationRule ObjectType="{x:Type system:Int32}"   />
            </Binding.ValidationRules>
        </Binding>
    </TextBox>

代码背后:

public class MyObject
{
    public object MyValue { get; set; }
}

public class MyValidationRule : ValidationRule
{
    public Type ObjectType { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        throw new NotImplementedException();
    }
}

也看看这个: 使用来自 XAML 的通用 IValueConverter

@Blam 评论值得考虑,要检查的范围通常适用于 integer 或双精度,对于其他类型,我会说您可以添加一个 boolean,它返回 object 的有效性,并在 object 本身内执行此类验证。

对于数字,您有RangeAttribute但它实际上并不是 WPF 验证基础结构的一部分。

您还有另一个验证选项:在这种情况下, INotifyDataErrorInfo验证发生在 object 内部。

我在这里写了一个冗长的答案: https://softwareengineering.stackexchange.com/questions/203590/is-there-an-effective-way-for-creating-complex-forms你可能会在上面找到有用的东西。

根据我的经验,我会说通用验证规则可能并不明智。

您应该将您的问题编辑得不那么笼统;-) 而是更具体一些,您会从这里的人那里得到更多帮助。 给出你试图验证的对象的一两个具体案例。

编辑

您还可以使用 BindingGroup 来验证 object:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void TextBox1_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        grid.BindingGroup.CommitEdit();
    }
}

public class Indices
{
    public int ColorIndex { get; set; }
    public string ColorPrefix { get; set; }
    public int GradientIndex { get; set; }
    public string GradientPrefix { get; set; }
}

public class ValidateMe : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var bindingGroup = value as BindingGroup;
        var o = bindingGroup.Items[0] as Indices;
        return new ValidationResult(true, null);
    }
}
<Window x:Class="WpfApplication6.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication6="clr-namespace:WpfApplication6"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Window.Resources>
        <wpfApplication6:Indices x:Key="Indices"
                                 ColorIndex="1"
                                 ColorPrefix="MyColor"
                                 GradientIndex="1"
                                 GradientPrefix="MyGradient" />
    </Window.Resources>
    <Grid x:Name="grid" DataContext="{StaticResource Indices}">
        <Grid.BindingGroup>
            <BindingGroup>
                <BindingGroup.ValidationRules>
                    <wpfApplication6:ValidateMe />
                </BindingGroup.ValidationRules>
            </BindingGroup>
        </Grid.BindingGroup>
        <TextBox TextChanged="TextBox1_OnTextChanged">
            <Binding Path="ColorIndex" UpdateSourceTrigger="PropertyChanged" />
        </TextBox>
    </Grid>
</Window>

使用范围属性:

    private void test()
    {
        Indices indices = new Indices();
        indices.ColorIndex = 20;

        var validationContext = new ValidationContext(indices);
        var validationResults = new List<System.ComponentModel.DataAnnotations.ValidationResult>();
        var tryValidateObject = Validator.TryValidateObject(indices, validationContext, validationResults,true);
    }

public class Indices
{
    [Range(1, 10)]
    public int ColorIndex { get; set; }

    public string ColorPrefix { get; set; }
    public int GradientIndex { get; set; }
    public string GradientPrefix { get; set; }
}

我有一个类似的问题:我需要一个特定于绑定源的ValidationRule ,即我希望源定义规则。

我最终使用了以下设置绑定的附加属性的方法,包括。 通过代码规则。

ICustomRuleProvider.cs :绑定源 (ViewModel) 必须实现的接口。

public interface ICustomRuleProvider
{
    ValidationRule CreateRule();
}

CustomRule.cs :Xaml 中用于创建所需绑定的附加属性,包括。 规则。

public class CustomRule
{
    public static ICustomRuleProvider GetProvider(DependencyObject obj)
    {
        return (ICustomRuleProvider)obj.GetValue(ProviderProperty);
    }

    public static void SetProvider(DependencyObject obj, ICustomRuleProvider value)
    {
        obj.SetValue(ProviderProperty, value);
    }

    public static readonly DependencyProperty ProviderProperty =

        DependencyProperty.RegisterAttached("Provider", typeof(ICustomRuleProvider), typeof(CustomRule), new FrameworkPropertyMetadata(null, CustomRule.OnProviderPropertyChanged));

    public static void OnProviderPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (!(sender is TextBox fe)) return;

        var provider = e.NewValue as ICustomRuleProvider;

        if (provider != null)
        {
            var b = new Binding("Value");
            b.ValidationRules.Add(provider.CreateRule());

            fe.SetBinding(System.Windows.Controls.TextBox.TextProperty, b);
        }
        else
        {
            BindingOperations.ClearBinding(fe, TextBox.TextProperty);
        }
    }
}

示例:务必定义xmlns:customRule="clr-namespace:...;assembly=..."

<TextBox customRule:CustomRule.Provider="{Binding}"/>

此实现是为将TextBoxText属性绑定到绑定源的“Value”属性而量身定制的,但这可以轻松扩展。

使用它我能够使用自定义(通用)转换器。

顺便说一句:我不同意自定义通用ValidationRule是一个“坏主意”,尽管用例可能有限。 在许多情况下,可能还需要实现自定义IValueConverter并将其分配给绑定,以便在从控件到源的过程中完全控制 object 值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM