Binding(绑定)
先上图,再解释
针对这个图,我们先来说说什么是Binding。
Binding就是一个桥梁,建立在数据和UI之间的桥梁。既然是数据驱动,那么我们就把数据称之为“源”,那么UI就是目的地,通过Binding将源数据送到指定的UI去展示。我们还可以在桥梁上进行数据的校验和转换,还可以控制数据的流向,单向或者双向。
最简单的绑定模式:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _name = "demo";
public string Name
{
get => _name;
set
{
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding Path=Name}" Width="200" Height="40" Grid.Row="0"/>
<Button Content="Button" Width="75" Height="40" Grid.Row="1" Click="Button_Click"/>
</Grid>
public partial class MainWindow : Window
{
private MainWindowViewModel model = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = model;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
model.Name += "-demo";
}
}
绑定的源与路径
只要是一个对象,并且通过属性公开了自己的数据,就可以作为绑定的源。如果想让这个对象能够在动通知自己的属性值已经发生了变化,那么就需要让这个对象实现INotifyPropertyChanged接口,并在属性的set语句中激发PropertyChanged事件。
1)把控件作为Binding源
<StackPanel Margin="20">
<TextBox Margin="5" Height="23" Text="{Binding Path=Value, ElementName=silder1}"/>
<Slider Margin="5" Maximum="100" Minimum="0" SmallChange="1" x:Name="silder1" Value="50"/>
</StackPanel>
2)Binding的方向和数据更新
Binding作为源和目标的桥梁,默认情况下能够将数据送达目标,也能够从目标返回到源。有时候只需要展示给用户、不允许用户修改,这时候可以把绑定的方向更改为源到目标的单向沟通。
控制Binding数据流向的属性是Mode,是一个枚举值。
public enum BindingMode
{
TwoWay,
OneWay,
OneTime,
OneWayToSource,
Default
}
这里解释一下Default值的特点。Default会根据目标的实际情况来确定,比如是可编辑的TextBox.Text属性,Default就会采用双向的模式。如果是TextBlock.Text属性,就会采用单向模式。
数据更新:UpdateSourceTrigger属性。也是一个枚举值。
public enum UpdateSourceTrigger
{
Default,
PropertyChanged,
LostFocus,
Explicit
}
其他属性:NotifyOnSourceUpdated和NotifyOnTargetUpdated两个bool型的属性,如果设置为true时,当源或者目标被更新后,Binding会触发SourceUpdated和TargetUpdated两个事件。我们可以通过监听这两个事件来找出哪些数据或者控件被更新了。
3)Path(路径)
Path属性用来指定Binding的源把哪些数据暴露给外界。如上例i,Silder控件作为了源,属性Value作为了Path,也就是将Value属性暴露给外界。
Binding支持多级路径,一路“点”下去。
4)没有Path的Binding
Binding源本身就是数据,且不需要Path来指明。比如string、int等基本类型作为源时。
5)Binding的指定源(Source)的方法
单个对象:实现INotifyPropertyChanged接口。
集合类型:List
DataTable或者DataView。
XMLDataProvider把XML数据指定为源,级联控件TreeView或者Menu等,可以把树状的XML作为源。
依赖对象Dependency Object指定为源。
把容器的DataContext指定为源:WPF的UI布局是树形结构,每个节点都是控件,每个节点都有DataContext。当一个Binding只知道自己的Path,而不知道自己的Source时,它会沿着UI元素树一路向树的根部找去,每路过的节点都要看看这个节点的DataContext有没有Path所指定的属性,如果有,那就使用这个对象作为自己的Source,否则会一路找下去。如果全部没有,也就说明了没有Source,也就没有了数据。
通过ElementName指定Source。
通过Binding的RelativeSource属性相对地指定Source,当控件关注自己的、自己的容器的或者自己内部元素的某个值时,就需要这种方法。
把ObjectDataProvider对象指定为Source,当数据源的数据不是通过属性而是通过方法暴露给外界时,我们可以使用这两种对象来包装数据源再把他们指定为Source。
通过LINQ检索到的数据对象作为Source。