深入浅出WPF-06.Binding(绑定)02

Binding对数据的校验和转换

1)数据校验,通过Binding的ValidationRules属性(Collection类型)进行校验。可以设置多个数据校验条件。

<Slider Margin="5" Maximum="100" Minimum="0" SmallChange="1" x:Name="silder1">
    <Slider.Value>
        <Binding Path="CurrentValue">
            <Binding.ValidationRules>
                <local:MyValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </Slider.Value>
</Slider>
public class MyValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (value != null && value is double input)
        {
            if (input > 0 && input < 100)
            {
                return new ValidationResult(true, null);
            }
        }

        return new ValidationResult(false, "can not null");
    }
}

ValidationRule是个抽象类,使用的时候需要创建他的派生类并实现Validate方法。如果通过校验,就把ValidationResult对象的IsValid属性设为true,否则设为false,并设置ErrorContent的消息内容。

校验的默认行为是认为来自于Source的数据总是正确的,只有来自目标Target的数据才可能出问题(Target多为UI控件,多数是用户输入的数据),为了就是不让输入的数据污染Source数据,所以才进行校验。Binding只有在Target被外部方法更新时才会校验(手动输入)。如果想在Source数据更新时Target也进行校验,需要将校验条件的ValidatesOnTargetUpdated设置为true。

当校验错误的时候Validate方法返回的ValidationResult对象,携带的错误信息如何显示?需要用到后面的知识---路由事件(EventRouted)。

如果Binding对象的NotifyOnValidationError="True",这时,当数据校验错误的时候Binding会像报警器一样发出一个信号,这个信号以Target为起点,沿着树进行传播,直到某个节点监听并处理了这个信号。信号处理完之后,可以决定这个信号是继续传播,还是终止(e.Handled = true;)。这就是路由事件,传递这个信号的过程叫做路由。

private MainWindowViewModel model = new MainWindowViewModel();
public Window1()
{
    InitializeComponent();
    this.DataContext = model;

    this.silder1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));
}

void ValidationError(object sender, RoutedEventArgs e)
{
    if (Validation.GetErrors(this.silder1).Count > 0)
    {
        //处理错误信息

        e.Handled = true;
    }
}

2)数据转换,当源Source端的Path所关联的数据与Target端目标属性数据展示不一致时,我们就可以通过添加数据转换器来实现。比如最常用的性别,在数据源Source端一般使用枚举值,Target端一般使用字符串或者图片来区分,这是我们就可以使用转换器来实现。

xaml代码:

<TextBlock Margin="5" Height="23" Text="{Binding SexType, Converter={StaticResource DtoShowStringConverter}}"/>

性别枚举值:

/// <summary>
/// 性别
/// </summary>
public enum SexType : byte
{
    /// <summary>
    /// 女
    /// </summary>
    Female = 0,
    /// <summary>
    /// 男
    /// </summary>
    Male = 1,
    /// <summary>
    /// 未知
    /// </summary>
    Null = 2
}

转换器:

public class DtoShowStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return null;

        string output = null;

        if (value is SexType input)
        {
            switch (input)
            {
                case SexType.Female:
                    output = "女";
                    break;
                case SexType.Male:
                    output = "男";
                    break;
                case SexType.Null:
                    output = "未知";
                    break;
                default:
                    break;
            }
        }

        return output;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

当数据从Source流向Target时,Convert方法被调用,反之,ConvertBack被调用。第一个参数是传入的值,第二个参数是返回的值的类型,第三个参数是用来传递额外信息的(对应的Binding中的ConverterParameter)。我们最常用的是Source流向Target(Convert方法),极少使用ConvertBack。

posted @ 2020-06-19 11:59  蜗牛的希望  阅读(206)  评论(0编辑  收藏  举报