首页 > 技术文章 > WPF数据绑定

lihuali 2021-04-28 10:13 原文

(一)Binding概念
Binding是数据的桥梁,它两端分别是Binding的源(Source)和目标(Target)。数据从那里来就是源(Source),数据要往那里去由是目标(Target)。一般情况下,Binding源是逻辑层的对象,Binding目标是UI层的控件对象。这样数据就会源源不断通过Binding送达UI层被展示,也就是完成了数据驱动UI的过程。

image

(二)绑定基础
定义一个只有Name属性的Student类,数据源是一个类的对象,一个对象可能会有很多数据,这些数据又通过属性暴露给外界。那些数据是想通Binding送达UI元素呢?也就是UI上的元素会关心对象那些属性值的变化,这个属性就称为Binding的路径(Path)。光有属性还不行,Binging是一种自动机制,当值发生变化后属性要有能力通知Binding让变化传递给UI元素。方法是在属性的set中激发一个PropertyChanged事件。

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

}

image

public partial class MainWindow : Window
{
    Student stu;
    public MainWindow()
    {
        InitializeComponent();
        stu = new Student();
        Binding binding = new Binding();
        binding.Source = stu;//设置Binding源为stu对象
        binding.Path = new PropertyPath("Name");//绑定对象的目标属性(Path)                                              
        BindingOperations.SetBinding(this.txtBox, TextBox.TextProperty, binding);//将Binding绑定到UI界面的txtBox对象的Text属性
        //或者用以下方式三合一以上操作
        //this.txtBox.SetBinding(TextBox.TextProperty, new Binding("Name") { Source =stu=new Student()});
    }
    private void btnClick_Click(object sender, RoutedEventArgs e)
    {
        stu.Name += "lhl-";//设置Name属性值  
    }
}

(三)Binding的数据源(Source)
Source:Binding的源是数据的来源,只要一个对象包含数据并能通过属性把数据暴露出来,它就能当作Binding的源来使用。但必须为Binding的Source指定合适的对象Binding才能正确工作。
(3.1) 使用DataContext作为源

DataContextFrameworkElement类的一个“依赖属性”,依赖属性有一个很重要的特点就是当你没有为控件的某个依赖属性显式赋值时,控件会把自己容器的属性“借过来”当作自己的属性值。实际上属性值沿着UI元素树向下传递了。

    <StackPanel Background="LightBlue">
        <StackPanel.DataContext>
            <local:Student Id="6" Name="lihuali" Age="40"></local:Student>
        </StackPanel.DataContext>
        <TextBox x:Name="txt1" Margin="5" FontSize="20" Text="{Binding Id}"></TextBox>
        <TextBox x:Name="txt2" Margin="5" FontSize="20" Text="{Binding Name}"></TextBox>
        <TextBox x:Name="txt3" Margin="5" FontSize="20" Text="{Binding Age}"></TextBox>
    </StackPanel>

使用场景:
①:当UI上的多个控件都使用Binding关注同一个对象时
②:当作为Source的对象不能被直接访问的时候——如窗体B内的控件想把A窗体内的控件当作自己的Binding源时,但A窗体内的控件是private访问级别,这时候可以把这个控件(或者控件的值)作为窗体A的DataContext(这个属性是public访问级别)从而暴露数据。

(3.2) 使用集合对象作为列表控件的ItemsSource
WPF中的列表式控件派生自ItemsControl类,自己然也继承了ItemsSource这个属性。ItemsSource属性可以接收一个IEnumerable接口派生类的实例作为自己的值(所有可被迭代遍历的集合都实现了这个接口,包括数组,List<T>等)。每个ItemsControl的派生类都具有自己对应的条目容器,例如:ListBox的条目容器是ListBoxItem,ComboBox条目容器是ComboBoxItem。ItemsSource里存放的一条一条的数据,条目容器把要展示数据显示出来。依靠Binding对象可以把数据条目和容器条目关联起来。只要我们为一个ItemsControl对象设置了ItemsSource属性值,ItemsControl对象就会自动迭代其中的数据元素、为每个数据元素准备一个条目容器,并使用Binding在条目容器与数据元素之间建立起关联。

image

<StackPanel x:Name="stackPanel" Background="LightBlue">
	<TextBlock Text="Student ID:" FontWeight="Bold" Margin="5"></TextBlock>
	<TextBox x:Name="txtID" Margin="5"></TextBox>
	<TextBlock Text="Student List:" FontWeight="Bold" Margin="5"></TextBlock>
	<ListBox x:Name="listBoxStudents" Height="110" Margin="5">
		<ListBox.ItemTemplate>
			<DataTemplate>
				<StackPanel Orientation="Horizontal">
					<TextBlock Text="{Binding Path=Id}" Width="30"/>
					<TextBlock Text="{Binding Path=Name}" Width="50"/>
					<TextBlock Text="{Binding Path=Age}" Width="30"/>
				</StackPanel>
			</DataTemplate>
		</ListBox.ItemTemplate>
	</ListBox>

</StackPanel>

public MainWindow()
{
    InitializeComponent();
    List<Student> stuList = new List<Student>()
            {
                new Student(){ Id=1,Name="Tom1",Age=40},
                new Student(){ Id=2,Name="Tom2",Age=41},
                new Student(){ Id=3,Name="Tom3",Age=42},
                new Student(){ Id=4,Name="Tom4",Age=43}
            };
    this.listBoxStudents.ItemsSource = stuList;
    // this.listBoxStudents.DisplayMemberPath = "Name";
    Binding binding = new Binding("SelectedItem.Id") { Source = this.listBoxStudents };
    this.txtID.SetBinding(TextBox.TextProperty, binding);

}

image

推荐阅读