Binding
DataContext属性被定义在FrameworkElement类里,这个类是WPF的基类,这意味着所有WPF控件都具备这个属性。在UI树上,每个结点都有DataContext。当一个Binding只知道Path而不知道Source时,会沿着UI树一路向树的根部找过去,每路过一个结点就查看该结点的DataContext是否具有Path所指定的属性。若有,那就把该对象作为自己的Source,否则继续找下去。如果到了树的根部还没有找到,那该Binding就没有Source,因而不会得到数据。事例如下:
XAML:
<StackPanel Background="LightBlue">
<StackPanel.DataContext>
<local:Student Id="6" Name="Tim" Age="29"/>
</StackPanel.DataContext>
<Grid>
<StackPanel>
<TextBox Text="{Binding Id}" Margin="5"/>
<TextBox Text="{Binding Name}" Margin="5"/>
<TextBox Text="{Binding Age}" Margin="5"/>
</StackPanel>
</Grid>
</StackPanel>
C#代码:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
由于Path也可省略成“.”,故有如下代码:
<StackPanel Background="LightBlue">
<StackPanel.DataContext>
<sys:String>Hello DataContext!</sys:String>
</StackPanel.DataContext>
<Grid>
<StackPanel>
<TextBox Text="{Binding .}" Margin="5"/>
<TextBox Text="{Binding .}" Margin="5"/>
<TextBox Text="{Binding .}" Margin="5"/>
</StackPanel>
</Grid>
</StackPanel>
DataContext是一个“依赖属性”,依赖属性有一个很重要的特点就是当没有为控件的某个依赖属性显示赋值时,控件就会把自己容器的属性值当作自己的属性值,实际上是属性值沿着UI元素树向下传递了。如下:
<Grid Background="LightBlue" DataContext="6">
<Grid>
<Grid>
<Grid>
<Button x:Name="btn" Content="OK" Click="btn_Click"/>
</Grid>
</Grid>
</Grid>
</Grid>
C#代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btn_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(btn.DataContext.ToString());
}
}
WPF中的列表式控件均派生自ItemsCotrol类,都继承了ItemsSource属性,该属性可接收一个IEnumerable接口派生类的实例作为自己的值。每个ItemsControl的派生类都具有自己对应的条目容器。ItemsSource里存放的是一条一条的数据,要想把数据显示出来就需要为它们穿上“外衣”,条目容器就起到数据外衣的作用。只要为一个ItemsControl对象设置了ItemsSource属性值,ItemsControl对象就会自动迭代其中的数据元素,为每个数据元素准备一个条目容器,并使用Binding在条目容器与数据元素之间建立起关联。如下:
XAML:
<StackPanel x:Name="stackPanel" Background="LightBlue">
<TextBlock Text="Student ID:" FontWeight="Bold" Margin="5"/>
<TextBox x:Name="textBoxId" Margin="5"/>
<TextBlock Text="Student List:" FontWeight="Bold" Margin="5"/>
<ListBox x:Name="listBoxStudents" Height="110" Margin="5"/>
</StackPanel>
C#代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Student> stuList = new List<Student>
{
new Student {Id = 1, Name = "Tom", Age = 20},
new Student {Id = 2, Name = "Tim", Age = 21},
new Student {Id = 3, Name = "Bruce", Age = 22}
};
this.listBoxStudents.ItemsSource = stuList;
this.listBoxStudents.DisplayMemberPath = "Name";
this.textBoxId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.listBoxStudents });
}
}