WPF-6: Binding -1

来自《深入浅出WPF》(刘铁猛)读书笔记

程序的本质是数据加算法。数据会在存储,逻辑和展示三个层流通,所以站在数据的角度上来说,这三个层都很重要。但算法在程序中的分布就不均匀了,对于一个三层结构的程序来说,算法分布在这几处:

A)数据库内部;

B)读取和写回数据;

C)业务逻辑;(程序的核心)

D)数据展示;

E)界面与逻辑的交互;

WPF作为一种专门的展示层技术,华丽的外观和动画只是它的表层现象,更重要的是它在深层次上帮助程序员把思维的重心固定在逻辑层,让展示层永远处于逻辑层的从属地位。WPF具有这种能力的关键是它引入了Data Binding概念以及与之配套的Dependency Property系统和DataTemplate。

从传统的Windows Form迁移到WPF之后,对于一个三层程序而言,数据存储层由数据库和文件系统来构建,数据传输和处理仍然使用.Net Framework的ADO.Net等基本类(与Windows Form等开发一样),展示层则使用WPF类库来实现,而展示层与逻辑层的沟通就使用Data Binding来实现。

如果把Binding比作数据的桥梁,那么它的两端分别是Binding的源(Source)和目标(Target)。

UI上的元素关心的是哪个属性值的变化,这个属性就称谓Binding的路径(Path)。Binding是一种自动机制,当值变化后属性要有能力通知Binding,让Binding把变化传递给UI元素。

怎样才能让一个属性具备这种通知Binding值已经变化的能力?方法是在属性的set语句中激发一个PropertyChanged事件。这个事件不需要我们自己声明,我们要做的是让作为数据源的类实现System.CompoenentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源后,Binding就会自动侦听来自这个接口的PropertyChanged事件。

class Student
{
    private string name;
    public string Name
    {
        get {return name; }
        set {name=value; }
    }
}

实现INotifyPropertyChanged接口的Student类:

class Student
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string name;
    public string Name
    {
        get {return name; }
        set {
            name=value;
            //invoke event
            if(this.PropertyChanged != null)
            {
                this.PropertyChanged.INvoke(this,new PropertyChangedEventArgs("Name"));
             }
         }
     }
}

接下来,我们将进入最重要的一步--使用Binding把数据源和UI元素连接起来。

public partial class Window1: Window
{
    Student stu;
    public Window1()
    {
        InitializeComponent();
        //prepare data source
        stu=new Student();
        //prepare binding
        Binding binding=new Binding();
        binding.source=stu;
        binding.Path=new PropertyPath("Name");
        //connect data source & target
        Binding.Operations.SetBinding(this.textBoxName,TextBox.TextProperty,binding);
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        st.Name += "Name";
    }
}

SetBinding(...)有3个参数:

1)用于指定Binding的目标,本例中是this.textBoxName;

2)用于为Binding指明把数据送达目标的哪个属性;

3)使用哪个Binding实例将数据源与目标关联起来。

Binding对源的要求并不苛刻--只要它是一个对象,并且通过属性Property公开自己的数据,它就能作为Binding的源。

A)把控件作为Binding源与Binding标记扩展

在C#代码中可以访问XAML代码中申明的变量但在XAML代码中却无法访问C#代码中申明的变量。

在C#代码中我们可以直接访问控件对象,所以一般不会使用Binding的ElementName属性,而是直接把对象赋值给Binding的Source属性。

this.textBox1.SetBinding(TextBox.TextProperty,new Binding("Value"){ElementName="slider1"});

可以简写为:

<TextBox x:Name="textBox1" Text="{Binding Value, ElementName=slider1}" BorderBrush="Black" Margin="5"/>

B)控制Binding的方向及数据更新

默认情况下数据既能通过Binding送达目标,也能从目标返回源。

控制Binding数据流向的属性是Mode,它的类型是BindingMode枚举,取值TwoWay,OneWay,OneTime,OneWayToSource,Default.这里Default是指Binding模式会根据目标的实际情况来确定,比如可编辑(TextBox.Text),Default就采用双向模式,若是只读(TextBlock.Text),则采用单项模式。

Binding的另外一个属性--UpdateSourceTrigger,它的类型是UpdateSourceTrigger枚举,可取值为PropertyChanged,LostFocus,Explicit,Default.

C)Binding的路径(Path)

实例textBox与slider关联:

<TextBox x:Name="textBox1" Text="{Binding Path=Value,ElementName=slider1}">

等效的C#代码:

Binding binding=new Binding() {Path=new PropertyPath("Value"), Source=this.slider1};
this.textBox1.SetBinding(TextBox.TextProperty,binding);

或者使用Binding的构造器简写为:

Binding binding=new Binding("Value") {Source=this.slider1};
this.textBox1.SetBinding(TextBox.TextProperty,binding);

可以使用索引器作为Path:让一个TextBox显示另一个textBox文本的第四个字符:

<StackPanel>
    <TextBox x:Name="textBox1" BorderBrush="Black" Margin="5" />
    (TextBox x:Name="textBox2" Text="{Binding Path=Text.[3],ElementName=textBox1,Mode=OneWay}" BorderBrush="Black" Margin="5" />
</StackPanel>

当使用一个集合或者DataView作为Binding源,如想把他的默认元素当做path使用,则:new Binding("/");

如果集合元素的属性仍然是一个集合,想把子集合中的元素当做path,则可以使用多级斜线的语法:

new Binding("/Name")
new Binding("ProvinceList.Name")
new Binding("Province/CityList.Name")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值