什么是绑定(Binding)

在winform中,我们常常会用到各种类型的赋值,例如:

  1. - button.Text="Hello";
  2. - label.Text="Hello";
  3. - ……

类似这种赋值操作,我们之所以不称之为绑定, 主要原因是因为他们大多数操作都是一次性的, 无论是数据还是按钮本身发生变化,对两者而言都是不可见的。

而绑定的概念则侧重于:两者的关联,协议与两者之间的影响。

首先,从一个简单的例子来理解什么是绑定。

  1. - 创建一个滑块控件,并且希望在滑动过程中,把值更新到另外一个静态文本上。代码如下:
  1. <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
  2. <Slider Name="slider" Width="200"/>
  3. <TextBlock Text="" HorizontalAlignment="Center"/>
  4. </StackPanel>
  1. Winform中,我们常规的做法会给滑块创建一个值改变事件,同时将滑块的值赋给文本。

接下来,我们只需要在静态文本中添加一小段绑定的声明,即可完成原本很复杂的操作:

  1. - `Text={Binding ElementName=slider,Path=Value}`
  2. * {Binding}:Binding的声明语法,一对尖括号,开头声明以Binding开始。
  3. * ElementName=:该声明意为,设置元素的名称
  4. * Path:设置关联元素的位置,上例中设置为元素的value属性。

那么该如何理解整句话的意义,翻译:静态文本TextBlockText属性将通过绑定的方式关联到元素名’slider’的value属性上。

  1. <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
  2. <Slider Name="slider" Width="200"/>
  3. <TextBlock Text="{Binding ElementName=slider,Path=Value}" HorizontalAlignment="Center"/>
  4. </StackPanel>
  1. 效果:

WPF绑定Binding - 图1

可以看到,在滑块不断的滑动过程中,TextBlock也在不断地发生变化,说明TextBlock已经得到了滑块滑动过程中的值变化,这种关联,我们称之为绑定,在WPF当中,绑定又分为很多种,而上面这种则是通过元素绑定的方式。

理解了基础的绑定之后,然后就是理解绑定的模式。

绑定的模式就类似我们商业中的合作,是一次性回报还是持续获益,是否可以单方面终止,是否具有投票权等,在WPF中绑定的模式又分为五种:

  • OneWay(单向绑定):当源属性发生变化更新目标属性,类似上面的例子中,滑动变化更新文本的数据。示例:
  1. <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
  2. <Slider Name="slider" Width="200"/>
  3. <TextBox Width="200" Text="{Binding ElementName=slider,Path=Value,Mode=OneWay}" HorizontalAlignment="Center"/>
  4. </StackPanel>
  1. 效果:

WPF绑定Binding - 图2

  • TwoWay(双向绑定):当源属性发生变化更新目标属性,目标属性发生变化也更新源属性。
    • 与单向绑定的区别可以理解为,前者只能打你,被打的不能还手。双向绑定的意思则是,你打我一巴掌,我也能回你一巴掌。示例:
  1. <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
  2. <Slider Name="slider" Width="200"/>
  3. <TextBox Width="200" Text="{Binding ElementName=slider,Path=Value,Mode=TwoWay}" HorizontalAlignment="Center"/>
  4. </StackPanel>
  1. 效果:

WPF绑定Binding - 图3

  • OneTime(单次模式):根据第一次源属性设置目标属性,在此之后所有改变都无效。
    • 如果第一次绑定数据源为0,那么无论后面如何改变2、3、4……都无法更新到目标属性上。示例:
  1. <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
  2. <Slider Name="slider" Width="200"/>
  3. <TextBox Width="200" Text="{Binding ElementName=slider,Path=Value,Mode=OneTime}" HorizontalAlignment="Center"/>
  4. </StackPanel>
  1. 效果:

WPF绑定Binding - 图4

  • OneWayToSource:和OneWay类型相似,只不过整个过程倒置。示例:
  1. <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
  2. <Slider Name="slider" Width="200"/>
  3. <TextBox Width="200" Text="{Binding ElementName=slider,Path=Value,Mode=OneWayToSource}"
  4. HorizontalAlignment="Center"/>
  5. </StackPanel>
  1. 效果:

WPF绑定Binding - 图5

  • Default:既可以是双向,也可以是单向,除非明确表明某种模式,否则采用该默认绑定。

绑定到非元素上

上面的代码中,使用的绑定方式是根据元素的方式:ElementName=xxx,如果需要绑定到一个非元素的对象,则有以下几个属性:

  • Source:指向一个数据源,示例:TextBox使用绑定的方式用Source指向一个静态资源ABC:
  1. <Window.Resources>
  2. <TextBox x:key="txt1">ABC</TextBox>
  3. </Window.Resources>
  4. <Grid>
  5. <TextBox Text="{Binding Source={StaticResource txt1},Path=Text}"}/>
  6. </Grid>
  • RelativeSource:使用一个名为RelativeSource的对象来根据不同的模式查找源对象。
  1. <StackPanel Width="200">
  2. <StackPanel Width="300"/>
  3. <!-- TextBlock 的Text值为200-->
  4. <TextBlock Text="{Binding Path=Width, RelativeSource={RelativeSource
  5. Mode=FindAncestor,AncestorType={x:Type StackPanel}}}"/>
  6. </StackPanel>
  • DataContext:从当前的元素树向上查找到第一个非空的DataContext属性为源对象。
  1. public partial class MainWindow : Wondow
  2. {
  3. public MainWindow()
  4. {
  5. InitializeComponent();
  6. this.DataContext = new Test(){Name = "小明"};
  7. }
  8. }
  9. public class Test
  10. {
  11. public string Name{get;set;}
  12. }
  1. <Grid>
  2. <!--绑定后台生成的Name-->
  3. <TextBlock Text="{Binding Name}"/>
  4. </Grid>

后台代码绑定简单文本与列表

创建一个PageModel类,定义一个ClassName为班级名称,和一个Students学生列表,后台代码:

  1. public partial class ManinWindow : Window
  2. {
  3. public MainWindow()
  4. {
  5. InitializeComponent();
  6. PageModel page = new PageModel();
  7. page.ClassName = "高二三班";
  8. page.Students = new List<Student>();
  9. page.Students.Add(new Student() {Name = "张三",Age = "18", Sex = "男"});
  10. page.Students.Add(new Student() {Name = "李四",Age = "19", Sex = "女"});
  11. page.Students.Add(new Student() {Name = "王五",Age = "20", Sex = "男"});
  12. this.DataContext = page;
  13. }
  14. }
  15. public class PageModel
  16. {
  17. public string ClassName{get;set;}
  18. public List<Student> Students{get;set;}
  19. }
  20. public class Student
  21. {
  22. public string Name{get;set;}
  23. public string Age{get;set;}
  24. public string Sex{get;set;}
  25. }
  1. <Grid>
  2. <Grid.RowDefinitions>
  3. <RowDefinition Height="20"/>
  4. <RowDefinition/>
  5. </Grid.RowDefinitions>
  6. <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
  7. <TextBlock Margin="5 0 0 0" Text="班级名称:"/>
  8. <TextBlock Margin="5 0 0 0" Text="{Binding ClassName}"/>
  9. </StackPanel>
  10. <DataGrid Grid.Row="1" ItemsSource="{Binding Students}" AutoGenerateColumns="False">
  11. <DataGrid.Columns>
  12. <DataGridTextColumn Binding="{Binding Name}" Header="名称"/>
  13. <DataGridTextColumn Binding="{Binding Age}" Header="年龄"/>
  14. <DataGridTextColumn Binding="{Binding Sex}" Header="性别"/>
  15. </DataGrid.Columns>
  16. </DataGrid>
  17. </Grid>
  1. 效果:

WPF绑定Binding - 图6