WPF学习笔记:Binding基础

我们知道WPF最重要的一个特性是数据驱动UI,Binding就是实现这个特性的桥梁,这个类把数据和界面控件关联起来。而且它还支持双向通信。当数据改变时,界面显示会自动改变;当界面内容改变时,后台的数据也会自动改变。当然这个双向通信是可以设置的。

1、Binding基础

binding源和目标。刚才说binding是一座桥梁,那源和目标就是桥梁的两端。一般来说,源就是数据,目标就是UI,但也可以反过来,也可以两端都是UI控件。下面看一个最简单的例子:

public class Student:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public int ID { get; set; }

        private string name;
        public string Name
        {
            get 
            {
                return name;
            }
            set
            {
                name = value;
                if(PropertyChanged!=null)
                {
                    PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }

        public int Age { get; set; }
    }

 我们定义了一个学生类,继承接口INotifyPropertyChanged,这个接口只定义了一个属性值改变的事件。

下面是界面代码:


    
        
        

下面我们在界面的构造函数中设置binding:

Student student = new Student();
        public Window4()
        {
            InitializeComponent();

            Binding binding = new Binding("Name") { Source = student };
            txtName.SetBinding(TextBox.TextProperty, binding);
        }

        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            student.Name += "Name";
        }

 Binding binding = new Binding("Name") { Source = student };这条语句的含义就是:把binding的源设置为student对象实例,Name为binding的访问路径,意思就是说这个binding关注的是student对象的Name属性。

txtName.SetBinding(TextBox.TextProperty, binding);这条语句把binding对象和界面控件关联起来,意思是把txtName文本框的TextProperty和binding对象关联起来,因为binding对象已经关联了student对象了Name属性,那么这两条语句的意思就是:txtName文本框关联了student对象的Name属性值。

那文本框怎么知道Name的属性值变了呢,答案就是Name属性的set代码块中。PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));这条语句触发了Name属性的值改变事件,因为binding对象关联了Name属性值,所以当binding对象接受到Name属性值改变后,就把Name属性值赋值给了txtName文本框。

当我们点击按钮后,文本框就会显示当前Name属性的值。

2、Binding的路径(Path)

path即对象的属性,关于path有很多种用法,下面我们逐一讲解:

1、索引器。看下面的例子:


    
        
        
    

我们把txtLength文本框的文本通过binding设置为txtName文本框文本的第二个字符,运行效果如下:

等效的c#代码:

Binding binding1 = new Binding("Text.[1]") { Source = txtName,Mode= BindingMode.OneWay };
txtLength.SetBinding(TextBox.TextProperty, binding1);

2、使用集合或者DataView作为Binding源时,如果我们想把它的默认元素当作path使用,则语法如下:

List stringList = new List() { "Tim", "Tom", "Blog" };
            txt1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = stringList });
            txt2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList, Mode = BindingMode.OneWay });
            txt3.SetBinding(TextBox.TextProperty, new Binding("/[1]") { Source = stringList, Mode = BindingMode.OneWay });

/斜杠即代表默认元素,集合的默认元素即第一个元素。

3、如果集合是嵌套的,我们想把子级集合中的元素作为path,则语法如下:

City c1 = new City() { Name = "黄冈" };
            City c2 = new City() { Name = "武汉" };

            Province p1 = new Province()
            {
                Name = "湖北",
                CityList = new List() { c1, c2 }
            };

            City c3 = new City() { Name = "广州" };
            City c4 = new City() { Name = "深圳" };
            Province p2 = new Province()
            {
                Name = "广东",
                CityList = new List() { c3, c4 }
            };

            Country country1 = new Country()
            {
                Name = "中国",
                ProvinceList = new List() { p1, p2 }
            };

            List countries = new List();
            countries.Add(country1);

            txt1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source= countries });
            txt2.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList.[1].Name") { Source = countries });
            txt3.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/Name") { Source = countries });
            txt4.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/CityList/Name") { Source = countries });

 运行效果如下:

WPF学习笔记:Binding基础_第1张图片

 4、没有指定path的binding。如果path的值为"."或者直接没有指定path,则表明binding的源本身就是数据,比如:string,int类型的数据。看下面的例子:


    
        菩提本无树,明镜亦非台。本来无一物,何处惹尘埃。
    
    
        
    

 

我们看到path=.,或者直接把path=.去掉都可以。

这条语句等效的c#代码:

string s = "菩提本无树,明镜亦非台。本来无一物,何处惹尘埃。";
lable1.SetBinding(TextBlock.TextProperty, new Binding(".") { Source = s });

 这里的"."也可以省略

 3、没有Source的Binding

DataContext属性被定义在FrameworkElement类里,这个类是WPF控件的基类,这意味着所有的WPF控件都具备这个属性。我们知道WPF的UI布局是树形结构的,这棵树的每个节点都是控件,由此我们推出一个结论:在UI元素树每个节点都有DataContext。这一点很重要,因为当一个Binding只知道自己的path而不知道自己的source时,它就会沿着UI元素树一路向树的根部找过去,每路过一个节点都要看看这个节点的DataContext是否具备path指定的属性。如果有,那就把这个对象作为自己的source;如果没有,那就继续找下去;如果到了树的根部还没有找到,那这个binding就没有source,因此也不会得到数据。

 我们看一个例子:

先定义一个Person类:

class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

 在xaml里面定义DataContext和Binding:


    
        
    
    
        
        
        
    

 我们把DataContext定义在Window标签内,给TextBox设置没有Source,只有Path的Binding。运行效果如下:

WPF学习笔记:Binding基础_第2张图片

 4、即没有指定Source也没有指定Path的Binding

 学习完前面的知识,理解这个其实很容易,我们看一个例子就明白了:


    
        Hello DataContext!
    
    
        
    

 

 

 

 

你可能感兴趣的:(WPF)