一、前言

​ Binding 的作用就是架在 SourceTarget 之间的桥梁,数据可以在这座桥梁的帮助下来流通。就像现实中的桥梁会设置一些关卡进行安检一样,Binding 这座桥上也可以设置关卡对数据的有效性进行校验。不仅如此,当两端要求使用不同的数据类型时,我们还可以为数据设置转换器。

​ Binding 用于数据有效性校验的关卡是它的 ValidationRules 属性,用于数据转换的关卡是它的 **Converter ** 属性。

二、Binding 对数据的校验

​ 例如:我们把一个 Slider 的Value 属性和 TextBox 的 Text 属性双向绑定在一起, Slider 的Value 的有效值是 0~100。当我们使用 Binding 绑定数值时,需要对该 Binding 的 ValidationRules 添加校验规则。具体实现如下所示:

​ 第一步:我们声明一个 RangeValidationRule 类编写校验规则,该类需要继承 ValidationRule 类(该类为抽象类),ValidationRule类的作用是提供创建自定义规则的一个方式,旨在检查用户输入的有效性。具体代码如下:

  public class RangeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (double.TryParse(value.ToString(), out var d))
{
if (d >= 0 && d <= 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "Validation value");
}
}

​ 第二步:对 TextBox 的 Text 属性进行 Binding 绑定,并对该 Binding 的 ValidationRules 添加一个校验规则 RangeValidationRule 类,具体实现如下:

    <StackPanel Grid.Row="0">
<TextBox x:Name="TextBox0" Margin="5" Height="50" VerticalContentAlignment="Center" ToolTip="{Binding ElementName=TextBox0,Path=e}">
<TextBox.Text>
<Binding ElementName="Slider0" Path="Value" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:RangeValidationRule ></local:RangeValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Slider x:Name="Slider0" Margin="5" Minimum="0" Maximum="100"></Slider>
</StackPanel>

然后,我们在文本框中,输入200,发现 TextBox 会显示红色边框,这表示数值是错误的,具体显示如下图:

三、Binding 的数据转换

​ 例如:我们实现如下一个程序,程序的用途是在列表里向玩家显示一些军用飞机的状态。数据类型如下:

  public enum Category
{
Bomber,
Fighter,
} public enum State
{
Available,
Locked,
Unknown,
} public class Plane
{
public Category Category { get; set; }
public string Name { get; set; }
public State State { get; set; }
}

​ 在UI中,Plane 的 Category 属性被映射为图片,State 被映射为 CheckBox 的 IsChecked 属性。具体转换规则如下:

public class CategoryToSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var c = (Category)value;
switch (c)
{
case Category.Bomber:
return "image/bomber.png";
case Category.Fighter:
return "image/fighter.png";
}
return new ValidationResult(false, "Validation Value");
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
} public class StateToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var s = (State) value;
switch (s)
{
case State.Available:
return true;
case State.Locked:
return false;
default:
return null;
}
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var b = (bool?) value;
switch (b)
{
case true:
return State.Available;
case false:
return State.Locked;
default:
return State.Unknown;
}
}
}

​ 我们添加一个 ViewModel 绑定到 UI 上,ViewModel 代码如下(属性变更可以阅读 ):

 public class Window3VM : NotifyProperty
{
private ObservableCollection<Plane> _planes;
private string _output; public ObservableCollection<Plane> Planes
{
get => _planes;
set => SetProperty(ref _planes, value);
} public string Output
{
get => _output;
set => SetProperty(ref _output, value);
}
}

​ 我们把 ViewModel 绑定到 UI 界面上,并把转换规则添加到对应的 Binding 上,具体实现如下:

<Window x:Class="UI.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UI"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:Window3VM}"
Title="Window3" Height="500" Width="600">
<Window.Resources>
<local:CategoryToSourceConverter x:Key="CTS"></local:CategoryToSourceConverter>
<local:StateToBoolConverter x:Key="STB"></local:StateToBoolConverter>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBox x:Name="TextBox0" Margin="5" Height="50" VerticalContentAlignment="Center" ToolTip="{Binding ElementName=TextBox0,Path=e}">
<TextBox.Text>
<Binding ElementName="Slider0" Path="Value" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:RangeValidationRule ></local:RangeValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Slider x:Name="Slider0" Margin="5" Minimum="0" Maximum="100"></Slider>
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="10">
<ListBox Margin="5" Height="200" ItemsSource="{Binding Path=Planes}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Margin="0,2,0,2" Width="50" Source="{Binding Path=Category,Converter={StaticResource CTS}}"></Image>
<TextBlock Margin="0,2,0,2" Width="200" TextAlignment="Center" VerticalAlignment="Center" Text="{Binding Path=Name}"></TextBlock>
<CheckBox Margin="0,2,0,2" Width="20" IsChecked="{Binding Path=State,Converter={StaticResource STB}}"></CheckBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Margin="5" Height="50" Content="Load" Click="ButtonLoad_OnClick"></Button>
<Button Margin="5" Height="50" Content="Save" Click="ButtonSave_OnClick"></Button> </StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Margin="5,5,5,0" Text="Output Data:"></TextBlock>
<TextBox x:Name="TextBox" Margin="5" Height="310" BorderBrush="Black" Text="{Binding Path=Output}"></TextBox>
</StackPanel>
</Grid>
</Grid>
</Window>

​ 如下所示,当我们点击Load 按钮后,加载出来列表,点击 Save 按钮后,把整个列表输出到右边的文本框:

/// <summary>
/// Window3.xaml 的交互逻辑
/// </summary>
public partial class Window3 : Window
{
private readonly Window3VM vm;
public Window3()
{
InitializeComponent(); this.DataContext= vm =new Window3VM();
} private void ButtonLoad_OnClick(object sender, RoutedEventArgs e)
{
vm.Planes=new ObservableCollection<Plane>()
{
new Plane(){Name = "B-1", Category = Category.Bomber, State = State.Unknown,},
new Plane(){Name = "F-35",Category = Category.Fighter,State = State.Unknown,},
new Plane(){Name = "B-6", Category = Category.Bomber, State = State.Unknown,},
new Plane(){Name = "F-22",Category = Category.Fighter,State = State.Unknown,},
new Plane(){Name = "J-20",Category = Category.Fighter,State = State.Unknown,},
};
} private void ButtonSave_OnClick(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (var plane in vm.Planes)
{
sb.Append($"{plane.Category},{plane.Name},{plane.State}\r\n");
} vm.Output = sb.ToString();
}
}

WPF 之 Binding 对数据的校验与转换(三)的更多相关文章

  1. WPF 基础 - Binding 对数据的转换和校验

    1. Binding 对数据的转换和校验 Binding 中,有检验和转换关卡. 1.1 数据校验 源码: namespace System.Windows.Data { public class B ...

  2. WPF之Binding对数据的转换(第五天)

    Binding在Slider控件与TextBox控件之间建立关联,值可以互相绑定,但是它们的数据类型是不同的,Slider是Double类型,Text为String.原来,Binding有一种机制称为 ...

  3. [转]深入浅出WPF(7)——数据的绿色通道,Binding

    本文转自:http://liutiemeng.blog.51cto.com/120361/95273 小序: 怎么直接从2蹦到7啦?!啊哦,实在是不好意思,最近实在是太忙了,忙的原因也非常简单——自己 ...

  4. 数据绑定(九)Binding的数据校验

    原文:数据绑定(九)Binding的数据校验 Binding用ValidationRules属性来校验数据的有效性,ValidationRules属性类型是Collection<Validati ...

  5. WPF之Binding初探

    初学wpf,经常被Binding搞晕,以下记录写Binding的基础. 首先,盗用张图.这图形象的说明了Binding的机理. 对于Binding,意思是数据绑定,基本用法是: 1.在xmal中使用 ...

  6. WPF之Binding深入探讨

    原文:http://blog.csdn.net/fwj380891124/article/details/8107646 1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在 ...

  7. WPF的Binding功能解析

    1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在存储.逻辑和界面三层之间流通,所以站在数据的角度上来看,这三层都很重要.但算法在3层中的分布是不均匀的,对于一个3层结构的 ...

  8. WPF之Binding深入探讨--Darren

    1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在存储.逻辑和界面三层之间流通,所以站在数据的角度上来看,这三层都很重要.但算法在3层中的分布是不均匀的,对于一个3层结构的 ...

  9. WPF自学入门(七)WPF 初识Binding

    今天记录一下Binding的基础和具体的使用方法,说起这个Binding,在WPF中,Binding是很重要的特征,在传统的Windows软件来看,大多数都是UI驱动程序的模式,也可以说事件驱动程序, ...

随机推荐

  1. react项目中实现搜索关键字呈现高亮状态(一)

    最近有个需求,在一个react项目中,实现搜索关键字呈现高亮状态.这个在普通的html文件中还好操作些,在react项目中有点懵逼了,因为react项目中很少操作dom,有点无从下手.但最后还是实现了 ...

  2. JAVA开发手册-Markdown

    前言 前 言 <Java 开发手册>是技术团队的集体智慧结晶和经验总结,经历了多次大规模一线实战的检验及不断完善.现代软件行业的高速发展对开发者的综合素质要求越来越高,因为不仅是编程知识点 ...

  3. python基础学习总结

    python管理cisco设备:http://www.linuxeye.com/program/1680.html 学习:https://www.liaoxuefeng.com/wiki/001431 ...

  4. redis存json数据时选择string还是hash

    redis存json数据时选择string还是hash 我们在缓存json数据到redis时经常会面临是选择string类型还是选择hash类型去存储.接下来我从占用空间和IO两方面来分析这两种类型的 ...

  5. TCP/IP协议栈在Linux内核中的运行时序分析

    网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...

  6. Nginx(六):配置解析之location解析

    nginx成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能.但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性. 那么,今天我们 ...

  7. 《进击吧!Blazor!》第一章 2.Hello Blazor

    第二次写专栏,开头还是不知道说什么,所以--先来段广告<进击吧!Blazor!>是本人与张善友老师合作的Blazor零基础入门系列视频,此系列能让一个从未接触过Blazor的程序员掌握开发 ...

  8. java虚拟机入门(一)-jvm基础

    转行学java之前,总是听着大佬们说着java像个渣男一样可以跨平台,一次编译到处运行,瞬间,我就坚定了学java的信念,哎呀妈呀,得劲.真的学java之后,好像渣男也不是那么好学的,尤其这货的必杀技 ...

  9. moco框架实现重定向

    一.重定向到百度 1.代码 2.运行结果 因为没哟填写别的,浏览器输入路径: localhost:8888/redirect 点击回车,跳转到百度 二.跳转到自己的网站 1.代码 2.运行结果 输入准 ...

  10. git的使用学习笔记4--创建分支

    1.在git上新建分支 查看本地分支 git branch 查看远程分支 git branch -a 创建一个分支 git checkout -b branch1 再次查看远程分支可以看到该分支 2. ...