WPF绑定入门

25 篇文章 8 订阅

一 概述

文章一开始,将给出一个使用WPF绑定的小实例。并以此为起点,逐步展开对WPF绑定知识的探讨。

 

二 实例演示

1新建WPF应用程序WpfBindingExp,下面是程序主画面的代码。

<pre name="code" class="html"><Window x:Class="WpfBindingExp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
	Title="MainWindow" Height="350" Width="525">
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="4*"></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="2" Orientation="Horizontal" Background="Aqua">
            <TextBlock Text="学号:" Height="30" Margin="10,0,0,0"/>
            <TextBlock x:Name="TextBlock_StudentId"  Width="100" Height="30" Margin="0,0,50,0"/>
            <TextBlock Text="姓名:" Height="30"/>
            <TextBlock x:Name="TextBlock_StudentName"  Width="100" Height="30"/>
        </StackPanel>
    </Grid>
</Window>
 

主画面被分割成4行,并在第3行放置容器控件StackPanel,再在容器控件中放入两个TextBlock控件,被命名为TextBlock_StudentId和TextBlock_StudentName,分别用来显示学生的学号和姓名信息。

2 在画面的后端代码中定义Student类,并定义类型为Student的属性,该属性被初始化为Id为1000,Name为“三五月儿”的学生对象。

using System.Windows;
namespace WpfBindingExp
{
    public partial class MainWindow : Window
    {
        public Student Student { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            Student = new Student() { Id = 10000, Name = "三五月儿" };
        }
    }
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

3 将Student对象的Id属性、Name属性分别与画面中的TextBlock_StudentId控件、TextBlock_StudentName控件的Text属性进行绑定,绑定使用以下代码完成。

this.TextBlock_StudentId.SetBinding(TextBlock.TextProperty, new Binding("Id") { Source = Student,Mode=BindingMode.TwoWay });          
this.TextBlock_StudentName.SetBinding(TextBlock.TextProperty, new Binding("Name") { Source = Student,Mode=BindingMode.TwoWay });  

4 执行程序,得到以下效果图。


图1 实例运行效果图

 

三 实例说明

下面将对实例代码进行分析说明。

1 控件的SetBinding方法

从下面这行代码开始吧。

this.TextBlock_StudentId.SetBinding(TextBlock.TextProperty, new Binding("Id") { Source = Student,Mode=BindingMode.TwoWay});    

代码中调用TextBlock控件的SetBinding方法完成Student对象的Id属性与TextBlock控件的Text属性的绑定工作。

SetBinding方法接受两个参数:

  • 第一个参数表示绑定的目标属性。这里传入的值为TextBlock.TextProperty,查看其定义,是一个类型为DependencyProperty的静态只读属性,说明它是一个依赖属性,只有依赖属性才可以作为绑定的目标属性。关于依赖属性,在这里不做过多说明。大家只要记住:作为绑定目标的属性必须是依赖属性
  • 第二个参数传入一个Binding对象。在构造这个Binding对象时,通过Binding类的构造函数传入绑定的源属性名,这里为“Id”(也可以通过设置Binding对象的Path属性来指定绑定对象的源属性名);随后通过设置Binding对象的Source属性来指定绑定的源对象,这里被设置为Student对象;再通过设置绑定的Mode属性来指定绑定的数据流动方向,这里被设置为TwoWay,表示双向绑定。构造好Binding对象后,就可以使用这个对象将源对象和目标对象关联起来,Binding对象是源对象与目标对象沟通的桥梁,也可以将其看成源对象和目标对象之间的数据传递通道。

 

2 Binding的Mode属性

关于Binding的Mode属性,这里稍微再啰嗦几句,Mode属性用来指定绑定的数据流动方向,该属性可以被设置为下列值之一:

  • OneWay:使用OneWay绑定时,每当源发生变化,数据就会从源流向目标。
  • OneTime: 绑定也会将数据从源发送到目标;但是,仅当启动了应用程序或DataContext发生更改时才会执行此操作,因此,它不会侦听源中的更改通知。
  • OneWayToSource: 绑定会将数据从目标发送到源。
  • TwoWay: 绑定会将源数据发送到目标,但如果目标属性的值发生变化,则会将它们发回给源。
  • Default: Binding的模式根据实际情况来定,如果是可编辑的就是TwoWay,只读的就是OneWay。

 

3 做个小小的总结

可见,要想完成绑定,首先需要构造用于绑定的Binding对象,该对象包含绑定的源对象(由Soure属性指定),绑定的源属性(由Path属性指定,也可通过构造函数来指定)以及绑定的数据流动方向(由Mode属性指定),当然还可以使用Binding类提供的其他属性来完成更多的设置,这里就不做一一说明了。

 

4 换种玩法

我们还可以将绑定的代码翻译成以下代码。

Binding binding = new Binding();
binding.Source = Student;
binding.Path = new PropertyPath("Id");
binding.Mode = BindingMode.TwoWay;           
this.TextBlock_StudentId.SetBinding(TextBlock.TextProperty, binding);


5 BindingOperations类的SetBinding方法

除了使用控件的SetBinding方法,还可以使用工具类BindingOperations的SetBinding方法来完成绑定操作:

BindingOperations.SetBinding(this.TextBlock_StudentId, TextBlock.TextProperty, binding);

工具类BindingOperations的SetBinding方法接收三个参数:

  • 第一个参数指定绑定的目标对象;
  • 第二个参数指定绑定的目标属性,必须是依赖属性;
  • 第三个参数指定使用哪个Binding对象将源对象与目标对象联系起来。

 

6 Binding模型示意图

通过前面的学习,可以总结出WPF绑定模型的基本构成。

 

图2 Binding模型示意图

Binding模型包括:源对象、目标对象及Binding对象。这里的Binding对象使用的是双向箭头,表示双向绑定。

在WPF中,常常使用Binding模型将数据以绑定的形式与界面元素联系起来。

 

7 升级我们的Student对象

只要稍加修改Student类的定义,便可以使实例中的绑定功能更上一层楼。

在升级Student类前,需要引入名称空间System.ComponentModel,因为升级Student类用到的INotifyPropertyChanged接口的定义就位于该名称空间中。

下面是升级后的Student类的代码。

public class Student:INotifyPropertyChanged
{
    private int id;
    public int Id
    {
        get 
        {
            return id;
        }
        set
        {
            id = value;
            NotifyPropertyChanged("Id");
        }
    }
 
    private string name;
    public string Name
    { 
        get
        {
            return name;
        }
        set 
        {
            name = value;
            NotifyPropertyChanged("Name");
        } 
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }  
}
使用升级后的Student对象作为绑定源的话,当Student对象的Id属性或者Name属性发生变化时,便会触发PropertyChanged事件,Binding对象接收到这个事件消息后,会得知名为Id或者Name的属性的值发生改变,便会通知Binding的目标对象更新变化后的值。为了验证这点,我们为显示学生姓名的TextBlock控件增加MouseEnter事件的处理方法,在该方法中修改Student对象Name属性的值,代码如下所示:

private void TextBlock_StudentName_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
    Student.Name = "sanwuyueer";
}
再次运行程序,将鼠标移至TextBlock_StudentName控件,得到以下效果图:

 

图3 使用升级后的Student对象进行绑定的效果

学生姓名由“三五月儿”变成了“sanwuyueer”,Name属性的变更是不是更新至画面啦。

 

8 为绑定对象增加值校验器和值转换器

其实,还可以为Binding对象指定值转换器,使用值转换器可以将值从一种类型转换成另外一种类型,关于值转换器,请阅读文章《WPF值转换器 》;还可以为绑定指定值校验器,通过值校验器可以校验数据的正确性,关于值校验器请阅读文章《WPF值转换器 》。至此,Binding模型中又增加了更多功能,也变得更加强大,升级后的Binding模型如下图所示。

 

图4 升级后的Binding模型示意图

  

9 在XAML中实现绑定

除了可以在后端代码中完成绑定操作,还可以在XAML代码中也可以完成这个操作。

为了在XAML中实现绑定,需要修改XAML代码,修改后的代码如下所示:

<Window x:Class="WpfBindingExp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local ="clr-namespace:WpfBindingExp"
        Title="MainWindow" Height="350" Width="525">
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="4*"></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="2" Orientation="Horizontal" Background="Aqua">
            <StackPanel.DataContext>
                <local:Student Id="10000" Name="三五月儿"/>
            </StackPanel.DataContext>
            <TextBlock Text="学号:" Height="30" Margin="10,0,0,0"/>
            <TextBlock x:Name="TextBlock_StudentId" Text="{Binding Path=Id,Mode=TwoWay}"  Width="100" Height="30" Margin="0,0,50,0"/>
            <TextBlock Text="姓名:" Height="30"/>
            <TextBlock x:Name="TextBlock_StudentName" Text="{Binding Path=Name,Mode=TwoWay}"  Width="100" Height="30" MouseEnter="TextBlock_StudentName_MouseEnter" />
        </StackPanel>
    </Grid>
</Window>

代码中使用xmlns:local ="clr-namespace:WpfBindingExp"引入名称空间WpfBindingExp,因为需要使用的Student类的定义位于该名称空间中。设置StackPanel控件的DataContext属性值为Student对象,这样一来,DataContext属性的值将作为StackPanel容器中所有控件绑定的数据源,而内部控件在进行绑定操作时就不再需要设置绑定的Source属性了,只需要设置绑定的Path属性和Mode属性即可。

下面将对DtataContext的工作原理进行说明。

 

10 使用DataContext属性

前面的实例中,在构造Binding对象时,需要使用Source属性指定绑定的源,其实也可以使用WPF控件的DataContext属性来指定绑定的源。DataContext属性被定义在FrameworkElement类里,这个类是所有WPF控件的基类,所以,WPF中所有控件都将具有该属性。这样一来,在WPF控件树(画面中所有控件构成了树形结构,简称为控件树)的每一个节点上都将具有该属性,所以,我们可以通过在控件树的任意节点设置其DataContext属性来指定绑定的源,而初始化绑定对象时就不再需要指定其Source属性了,只需要设置其Path属性即可。当一个Binding对象只知道自己的Path而不知道Source时,它就会沿着控件树一路向树的根部找去,每路过一个节点就看看该节点的DataContext中是否具有Path指定的属性,若有就将该对象作为绑定的Source,若没有,就继续找下去,直到找到为止,如果到了树根都还没有找到满足条件的Source,那就得不到需要的数据了。所以,在本文的实例中,也可以通过设置Grid或者Window的DataContext属性来指定绑定的数据源,同样可以达到要求。

<Grid.DataContext>
    <local:Student Id="10000" Name="三五月儿"/>
</Grid.DataContext>

在实际开发时,往往会将用于绑定的所有对象封装进一个类,再将该类的实例指定为Window的DataContext属性,这样一来,画面中所有控件的绑定源均可以在Window的DataContext中找到,下面所给的实例就是这么干的。

 

四 再来一个实例

请忘掉前面的代码吧,下面给出一个新实例,也可以说是一个升级版的实例。

下面是完整的代码。关于该实例不作任何说明,大家就自己去研究吧。

1 XAML代码

<Window x:Class="WpfBindingExp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local ="clr-namespace:WpfBindingExp"
        Title="MainWindow" Height="350" Width="525">
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition Height="4*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock x:Name="TextBlock_Title" Text="{Binding Path=Title}" FontSize="32" Grid.Row="1"  Width="100" Height="50"/>
        <StackPanel Grid.Row="2" Orientation="Horizontal" Background="Aqua" DataContext="{Binding Path=Student}">
            <TextBlock Text="学号:" Height="30" Margin="10,0,0,0"/>
            <TextBlock x:Name="TextBlock_StudentId" Text="{Binding Path=Id,Mode=TwoWay}"  Width="100" Height="30" Margin="0,0,50,0"/>
            <TextBlock Text="姓名:" Height="30"/>
            <TextBlock x:Name="TextBlock_StudentName" Text="{Binding Path=Name,Mode=TwoWay}"  Width="100" Height="30" MouseEnter="TextBlock_StudentName_MouseEnter" />
        </StackPanel>
        <ListBox Grid.Row="3" x:Name="ListBox_CourseList" ItemsSource="{Binding Path=CourseList}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock x:Name="TextBlock_CourseId" Text="{Binding Path=Id}" Width="100" Height="30" Margin="10,0,10,0"/>
                        <TextBlock x:Name="TextBlock_CourseName" Text="{Binding Path=Name}" Width="100" Height="30" Margin="10,0,10,0"/>
                        <TextBlock x:Name="TextBlock_CourseTeacher" Text="{Binding Path=Teacher}" Width="100" Height="30" Margin="10,0,10,0"/>
                        <TextBlock x:Name="TextBlock_CourseScore" Text="{Binding Path=Score}" Width="100" Height="30" Margin="10,0,10,0"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

2 CS代码

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.ComponentModel;
using System.Collections.Generic;
 
namespace WpfBindingExp
{
  
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new BindingExpViewModel(); 
        }
    }
    public class Student:INotifyPropertyChanged
    {
        private int id;
        public int Id
        {
            get 
            {
                return id;
            }
            set
            {
                id = value;
                NotifyPropertyChanged("Id");
            }
        }
 
        private string name;
        public string Name
        { 
            get
            {
                return name;
            }
            set 
            {
                name = value;
                NotifyPropertyChanged("Name");
            } 
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }  
    }
 
    public class Course
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Teacher { get; set; }
        public int Score { get; set; }
    }
 
    public class BindingExpViewModel
    {
        public string Title { get; set; }
 
        public Student Student { get; set; }
 
        public List<Course> CourseList { get; set; }
 
        public BindingExpViewModel()
        {
            Title = "公告";
            Student = new Student() { Id = 10000, Name = "三五月儿" };
            CourseList = new List<Course>() 
            {
                new Course(){Id = 223,Name="操作系统",Teacher="张三",Score=85},
                new Course(){Id = 224,Name="数据库",Teacher="李月",Score=81},
                new Course(){Id = 223,Name="数据结构",Teacher="乌拉",Score=80}
            };
        }
 
    }
}

3 运行程序后的效果图。

 

图5 升级版示例程序的运行效果图

 

五 总结

本文通过实例介绍了WPF绑定中最基础的一些知识点,有关绑定更多知识的介绍会在以后的文章中慢慢来说。

 

 

 

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值