5-3Binding对数据的转换和校验

Binding对数据的转换和校验

Binding作为Source和Target之间的桥梁,可以在桥梁上设置校验,如果桥梁两端要求的数据类型不同时,还可以设置类型转换器。

Binding数据校验

Binding的ValidationRules属性类型Collection,即可以设置多个校验规则。

<StackPanel>
    <TextBox x:Name="textBox1" Margin="5"/>
    <Slider x:Name="slider" Minimum="0" Maximum="100" Margin="5"/>
</StackPanel>
public class RangeValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        double d = 0;
        if (double.TryParse(value.ToString(),out d))
        {
            if (d>=0 && d<=100)
            {
                return new ValidationResult(true, null);
            }
        }
        return new ValidationResult(false, "错误内容");
    }
}

Binding binding = new Binding("Value") { Source = this.slider };
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rvr = new RangeValidationRule();
binding.ValidationRules.Add(rvr);
this.textBox1.SetBinding(TextBox.TextProperty, binding);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1h8v3tUT-1667456214635)(5-3Binding数据的转化与校验.assets/image-20221102191713621.png)]

Binding默认来自Source的数据总是正确的,只有Target的数据才有问题。所以默认来自Source的数据更新Target时不会进行校验。如果要校验Source则要把ValidationRule的ValidatesOnTargetUpdated属性设置为True。

显示校验错误内容

将Binding对象的NotifyOnValidationError属性设置为true,这样失败时Binding触发信号,该信号会在以Binding对象的Target为起点的UI元素树上进行传播。信号每到达一个节点就要查看这个节点是否设置了对该信号的监听器,如果设置了监听器就会被触发。程序员也可以设置信号的继续传播还是就此终止,这就是路由事件,信号在UI元素树上传递的过程就称为路由

Binding binding = new Binding("Value") { Source = this.slider };
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rvr = new RangeValidationRule();

binding.ValidationRules.Add(rvr);
binding.NotifyOnValidationError = true;

this.textBox1.SetBinding(TextBox.TextProperty, binding);
this.textBox1.AddHandler(Validation.ErrorEvent,new RoutedEventHandler( (sender, e) =>
{
    if (Validation.GetErrors(this.textBox1).Count > 0)
    {
        this.textBox1.ToolTip = Validation.GetErrors(this.textBox1)[0].ErrorContent.ToString();
    }
}));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wlJrmyPI-1667456214637)(5-3Binding数据的转化与校验.assets/image-20221102193701203-16673891386752.png)]

Binding的数据转换

Binding的转换机制(Data Convert),当Source端的Path属性类型和Target所需要的类型不一致时使用。

自定义Converter要继承IValueConverter

public interface IValueConverter
{
    //从source到Target时使用
    object Convert(object value, Type targetType, object parameter, CultureInfo culture);
    object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
//Mode会影响方法的调用,如TwoWay则两个方法都可能被调用,OneWay则知道用Convert

案例:

//种类
public enum Category { Bomber,Fighter}
//状态
public enum State { Available,Locked,Unknow}
//飞机
public class Plane
{
    public Category Category { set; get; }
    public string Name { set; get; }
    public State State { set; get; }
}
public class CategoryToSourceConverter : IValueConverter
{
    //将Category转换为Uri
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Category c = (Category)value;
        switch (c)
        {
            case Category.Bomber:
                return @"\Icons\bomber.png";
            case Category.Fighter:
                return @"\Icons\fighter.png";
            default:
                return null;
        }
    }
    //单向不会被调用
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
public class StateToNullableBoolConvert : IValueConverter
{
    //state转换为bool
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        State s = (State)value;
        switch (s)
        {
            case State.Available:
                return true;
            case State.Locked:
                return false;
            case State.Unknow:
            default:
                return null;
        }
    }
    //bool转State
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool? b = (bool?)value;
        switch (b)
        {
            case true:
                return State.Available;
            case false:
                return State.Locked;
            case null:
            default:
                return State.Unknow;
        }
    }
}
<Window.Resources>
    <local:CategoryToSourceConverter x:Key="cts"/>
    <local:StateToNullableBoolConvert x:Key="stnb"/>
</Window.Resources>
<StackPanel Background="LightBlue">
    <ListBox x:Name="lstBoxPlane" Height="160" Margin="5">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Width="20" Height="20" Source="{Binding Path=Category,Converter={StaticResource cts}}"/>
                    <TextBlock Text="{Binding Path=Name}" Width="60" Margin="80,0"/>
                    <CheckBox IsThreeState="True" IsChecked="{Binding Path=State,Converter={StaticResource stnb}}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button x:Name="btnLoad" Content="Load" Height="25" Margin="5" Click="BtnLoad_Click"/>
    <Button x:Name="btnSave" Content="Save" Height="25" Margin="5" Click="BtnSave_Click"/>
</StackPanel>
private void BtnLoad_Click(object sender, RoutedEventArgs e)
{
    List<Plane> planes = new List<Plane>()
    {
        new Plane(){Category=Category.Bomber,Name="B-1",State=State.Unknow},
        new Plane(){Category=Category.Bomber,Name="B-2",State=State.Unknow},
        new Plane(){Category=Category.Fighter,Name="f-3",State=State.Unknow},
        new Plane(){Category=Category.Fighter,Name="f-1",State=State.Unknow},
        new Plane(){Category=Category.Bomber,Name="B-1",State=State.Unknow},
        new Plane(){Category=Category.Bomber,Name="B-1",State=State.Unknow},
        new Plane(){Category=Category.Fighter,Name="f-1",State=State.Unknow},
    };
    this.lstBoxPlane.ItemsSource = planes;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YFBSqpMr-1667456214637)(5-3Binding数据的转化与校验.assets/image-20221103095341940.png)]

private void BtnSave_Click(object sender, RoutedEventArgs e)
{
    StringBuilder sb = new StringBuilder();
    foreach (Plane p in lstBoxPlane.Items)
    {
        sb.AppendLine($"Category={p.Category},Name={p.Name},State={p.State}");
    }
    Debug.Write(sb.ToString());
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7qfZ1ILZ-1667456214637)(5-3Binding数据的转化与校验.assets/image-20221103095413207.png)]

多路Binding

当需要的信息不止一个数据源时,可以使用MultiBinding,MultiBinding具有一个Bindings的属性,类型是Collection,处在这个集合中的Binding对象可以拥有自己的数据校验和转换机制,他们汇总起来的数据将传递到Target上。

案例:用于新用户注册的UI,第一、二个TextBox要求内容一致;第三、四TextBox要求内容一致;当所有TextBox内容全部符合要求时,Button可用。

<StackPanel Background="LightBlue">
    <TextBox x:Name="txt1" Height="23" Margin="5"/>
    <TextBox x:Name="txt2" Height="23" Margin="5"/>
    <TextBox x:Name="txt3" Height="23" Margin="5"/>
    <TextBox x:Name="txt4" Height="23" Margin="5"/>
    <Button x:Name="btn" Content="Submit" Width="80" Margin="5"/>
</StackPanel>
//继承自IMultiValueConverter
public class LogonMultiBindingConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))&& values[0].ToString() == values[1].ToString() && values[2].ToString() == values[3].ToString())
        {
            return true;
        }
        return false;
    }
    //不会被调用
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

使用MultiBinding

 //准备基础的Binding
 Binding b1 = new Binding("Text") { Source = this.txt1 };
 Binding b2 = new Binding("Text") { Source = this.txt2 };
 Binding b3 = new Binding("Text") { Source = this.txt3 };
 Binding b4 = new Binding("Text") { Source = this.txt4 };
 //准备MultiBinding
 MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay };
 //注意添加的顺序,它决定了汇集到convert里数据的顺序
 mb.Bindings.Add(b1);
 mb.Bindings.Add(b2);
 mb.Bindings.Add(b3);
 mb.Bindings.Add(b4);
 mb.Converter = new LogonMultiBindingConverter();
 this.btn.SetBinding(Button.IsEnabledProperty, mb);

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步、步、为营

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值