06_深入浅出话Binding

备注:类关系结构图如下:

在这里插入图片描述

Binding

Binding基础
  1. Binding作用:目的是实时变化,Binding的源是逻辑层的对象,Binding目标是UI层控件对象。

  2. 一个例子:

    class Student: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private string name;
        public string Name
        {
            get{return name;}
            set
            {
                name = value;
                // 激发事件
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"))
            }
        }
    }
    
    // xaml中
    <TextBox x:Name="textBoxName" BorderBrush="Black" Margin="5" />
    <Button Content="Add Age" Margin="5" Click="Button_Click" />
    
    // xaml对应的cs中
    Student stu;
    public Window1()
    {
        InitialComponent();
    
        // 准备数据源
        stu = new Student();
    
        // 准备Binding
        Binding binding = new Binding();
        binding.Source = stu;
        binding.Path = new PropertyPath("Name");
    
        // 使用Binding链接数据源和Binding目标
        BindingOperations.SetBinding(this.textBoxName, TextBox.TextProperty, binding);
    
        // 备注:上面这些也可以合并成为一句
        this.textBoxName.SetBinding(TextBox.TextProperty, new Binding("Name"){Source = stu = new Student()});
    }
    
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        stu.Name += "Name";
    }
    

    效果展示:
    在这里插入图片描述

  3. 模型:
    在这里插入图片描述

Binding的源和路径

备注:上面写的Student就可以作为源,下面讨论不同情况下的源。

1. 把控件作为Binding源与Binding标记扩展

在这里插入图片描述
备注:

  • 在C#代码中可以访问XAML代码中声明的变量但XAML代码中无法访问C#代码中声明的变量,因此,想要在XAML中建立UI元素和逻辑层对象的Binding还要颇费周折,把逻辑层对象声明为XAML代码中资源,然后使用资源。
  • 上面也可简写成如下,参数->构造函数:
    <TextBox x:Name="textBox1" Text="{Binding Value, ElementName=slider1}" BorderBrush="Black" Margin="5" />
  • 与之等价的C#代码是
    this.textBox1.SetBinding(TextBox.TextProperty, new Binding("Value"){ElementName="slider1"});
2. 控制Binding的方向及数据更新
  • 控制Binding数据流向的属性是Mode,他的类型是BindingMode枚举。BindingMode可取值为TwoWay、OneWay、OneWayToSource和Default。这里Default值是指Binding的模式会根据目标的实际情况来确定,比如若是可编辑的(如TextBox.Text属性),Default就采用双向模式;若是只读的(如TextBlock.Text)则采用单向模式。
  • Binding的另一个属性—UpdateSourceTrigger,他的类型是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFocus、Explicit和Default。
3. Binding的路径(Path)
  • 一般情况下:
    <TextBox x:Name="textBox1" Text="{Binding Path=Value, ElementName=slider}">
    等效的C#代码是:
    Binding binding = new Binding(){Path=new PropertyPath("Value"), Source=this.slider};
    this.textBox1.SetBinding(TextBox.TextProperty, binding);
    或者:
    this.textBox1.SetBinding(TextBox.TextProperty, new Binding("Value"){Source=this.slider});
    
  • 文本长度
    Text.Length 替代上面的 Value
    备注:同时 Mode="OneWay"  和 Source位置一样,作为字段名赋值
    
  • 集合类型的索引器又称为带参属性,既然是属性,索引器也能作为Path来使用。
    Text.[3] 或者 Text[3]
4. 没有path的binding

在这里插入图片描述
备注:

  • Binding源本身就是数据且不需要path来指定,典型的string、int等基本类型就是这样。
  • 所以在xaml代码中可以写".“也可以不写,但是在C#代码中”."不能省略。
  • 上面代码在C#代码中如下:
    // xaml中不写如下
    Text = "{Binding Source={StaticResource ResourceKey = myString}}"
    // C#如下
    string myString = "菩提本无树,明镜亦非台。本来无一物,何处染尘埃。"
    this.textBlock.SetBinding(TextBlock.TextProperty, new Binding("."){Source= myString});
    
5. 没有Source的Binding–使用DataContext作为Binding源
  • DataContext属性被定义在FrameworkElement类里,这个类是WPF控件的基类,所以UI元素树的每个节点都有DataContext。

  • 当一个Binding只知道自己的Path而不知道自己的Source时,他会沿着UI元素树一路向书的根部找过去。

  • 如果找到根部还没有找到Path对应的Source,那这个Binding就没有Source,因而也不会得到数据。

  • 示例代码:

    public class Student
    {
      public int Id{get; set;}
      public string Name{get; set;}
      public int Age{get; set;}          
    }
    

    在这里插入图片描述

  • 当Binding的Source本身就是数据,不需要使用属性来暴露数据,Binding的Path可以设置为“.”,也可以省略不写,同时Source也可以省略不写,所以有如下:

    <StackPanel>
        <TextBlock Text="{Binding}" Margin="5" />
        <TextBlock Text="{Binding}" Margin="5" />
        <TextBlock Text="{Binding}" Margin="5" />
    </StackPanel>
    
6. 使用集合对象作为列表控件的 ItemSource

备注:

  • WPF中列表控件们派生自 ItemsControl 类,自然也就继承了 ItemsSource 属性,ItemsSource 属性可以接受一个 IEnumerable 接口派生类作为自己的值(所有可以被迭代遍历的集合都实现了这个接口)。

代码例子:
在这里插入图片描述

7. 使用 DataTable 数据作为 Binding 的源

代码例子:

  • ListBox 中 DataTable 作为源在这里插入图片描述
    备注:this.listBoxStudents.ItemsSource = dt.DefaultView;,其中的 DataTable 的 DefaultView 属性是一个 DataView 类型的对象,DataView 类实现了 IEnumerable 接口,所以可以被赋值给 ListBox.ItemsSource 属性。
  • ListView 控件中 DataTable 作为源(自定义格式)。在这里插入图片描述
    在这里插入图片描述

备注:DataTable 不能直接拿来作为 ItemsSource 赋值,不过,当你把 DataTable 对象放在一个对象的 DataContext 属性里,是可以的,如下:

private void Button_Click(object sender, RoutedEventArgs e)
{
    DataTable dt = this.Load();

    this.listViewStudents.DataContext = dt;
    this.listViewStudents.SetBinding(ListView.ItemsSourceProperty, new Binding());
}
8. 使用 XML 数据作为 Binding 的源
  1. 代码例子1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
备注:
- 需要注意的是,当使用 XML 数据作为 Binding 的 suorce 时,我们将使用 XPath 属性,而不是 Path 属性来指定数据的来源。
- 使用 @ 符号加字符串表示 XML 元素的 Attribute,不加 @ 符号的字符串表示子级元素。
2. 代码例子2

在这里插入图片描述

在这里插入图片描述
备注:需要注意的是,如果把 XmlDataProvider 直接放在 XML 代码里,那么它的 XML 数据需要放在 <x:XData> ... </x:XData>标签里。

8. 使用 LINQ 数据作为 Binding 的源
  1. LINQ 查询的结果是一个 IEnumerable 类型的对象,而 IEnumerable 又派生自 IEnumerable,所以它可以作为列表控件的 ItemsSource 来使用。
  2. 不同情况下写法。
    • 直接泛型
      在这里插入图片描述
    • 如果数据存放在一个已经填充好的 DataTable 对象里
      在这里插入图片描述
    • 如果数据存放在 XML 文件里,如下
      在这里插入图片描述
9. 使用 Binding 的 RelativeSource
  1. 有明确数据源的时候我们可以通过 Source 和 ElementName 赋值的方法让 Binding 与之关联,有些时候不确定对象叫什么名字,只知道他们 UI 之间的依赖关系,可以使用 RelativeSource 属性。
  2. 代码例子:
    • 寻找祖先在这里插入图片描述
      在这里插入图片描述
    • 寻找自己
      在这里插入图片描述
    • 备注:RelativeSource 类中的 Mode 属性的类型是 RelativeSourceMode 枚举,他的取值有: PreviousData、TemplatedParent、Self、FindAncestro
Binding 的数据校验和转换
Binding 的数据校验

下面程序是 UI 上有一个 TextBox 和 Slider,然后后台 Binding 关联起来,Slider 是源,TextBox 为目标,Slider 取值范围是0-100,需要校验的是 TextBox 里输入的值是不是0-100范围内。
在这里插入图片描述
在这里插入图片描述
备注:

  • TextBox 中输入0-100程序显示正常,但是输入这个区间之外的值或不能被解析的值时,TextBox 会显示红色边框,表示值时错误的,不能传递给 Source。
  • Binding 只在 Target 被外部方法更新时才校验数据,而来自 Binding 的 Source 数据更新 Target 是不会校验的,如果想改变这种行为,可以将校验条件的 ValidatesOnTargetUpdated 属性设为 true。
    在这里插入图片描述
  • 默认校验错误之后,错误信息是不显示的,如果想显示,需要将 Binding 对象的 NotifyOnValidationError 属性设置 true,这样 error 信号才会在 UI 元素树上往上传递。
    在这里插入图片描述在这里插入图片描述
Binding 的数据转换
  1. 引入
    • 作用于 Source 和 Target 之间,其实现的接口,Convert 是正方向,ConvertBack 是反方向,就是从 Target 到 Source 需要经过的转换。Binding 对象的 Mode 属性会影响到两个方法的调用,如果是 TwoWay 两个方法都有可能被调用,如果是 OneWay 则只有一个 Convert 被调用。
    • 简单的转换WPF已经帮我们做了,有些复杂的需要我们自己写。
  2. 代码例子
    在这里插入图片描述
    在这里插入图片描述
    备注:Convert 参数:第一参数 object 可以在方法体内对实际类型进行判断。第二个参数用于确定方法的返回类型。第三个参数用于把额外的信息传入方法,若需要传递多个信息可以把信息彷如一个集合对象来传入方法。
    在这里插入图片描述
    在这里插入图片描述
MultiBinding (多路 Binding)
  1. 引入:有时候 UI 需要显示的信息由不止一个数据来源决定,这时候就需要使用 MultiBinding。凡是能使用 Binding 对象的场合都能使用 MultiBinding,其类型是 Collection,通过这个属性把一组 Binding 对象聚合起来,出在这个集合中的 Binding 对象可以拥有自己的数据校验和转换机制。

  2. 代码例子

    • 需求:考虑这样一个需求,有一个用于新用户注册的UI(包含4个 TextBox 和一个 Button),还有如下一些限定:
      • 第一、二个 TextBox 输入用户名,需求内容一致。
      • 第三、四个 TextBox 输入用户 E-Mail,要求内容一致。
      • 当 TextBox 的内容全部符合要求的时候,Button 可用。 在这里插入图片描述
        在这里插入图片描述
    • 备注:
      • MultiBinding 对于添加子级 Binding 的顺序是敏感的,因为这个顺序决定了汇集到 Converter 里数据的顺序。
      • MultiBinding 的 Converter 实现的是 INultiValueConverter 接口。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值