数据绑定
数据绑定连接源数据(Source)和目标数据(Target)
当数据变化的时候,通知绑定的目标,需要实现额外的接口。
比如INotifyPropertyChanged。
BindingOperations.SetBinding()的三个参数,
第一个目标Traget,
第二个是目标属性,这是一个依赖属性。Static readonly dependencyProperty
第三个是Binding对象。(包含源Source,Path 源的属性,Convert 转换器)
数据源要求(Source):是一个对象,具有广阔的Property属性。
1.控件作为数据源
<StackPanel> <TextBox x:Name=”op” Text="{Binding ElementName=s1, Path=Value}" ></TextBox> <Slider x:Name="s1" Maximum="100"></Slider> </StackPanel> |
效果:
与之等效的c#语句:
BindingOperations.SetBinding(op, TextBox.TextProperty,new Binding() { Source =s1,Path =new PropertyPath("Value") }); |
Mode属性:
绑定的模式:TwoWay,OneWay,OmnTime,OmneWayToSource,Default
默认绑定模式跟目标控件的编辑类型有关,如果目标控件是可编辑的,则Default是是双向模式,如果目标控件时只读的,则Default时单向的。
UpdateSourceTrigger属性:
更新触发模式,Default,PropertyChanged,LostFocus,Exlicit
这里默认时失去焦点才进行数据跟新的,可以设置触发模式为ProperChanged,则只要修改数量,就可以触发。
Path:
Path时绑定源数据,具有很多的形式。由于源数据本质上时一个树对象,所以需要注意取的时什么数据。
Student student = new Student(); student.Name = "测试11"; BindingOperations.SetBinding(op, TextBox.TextProperty,new Binding() { Source = student, Path = new PropertyPath("Name"),Mode = BindingMode.OneWay });
public class Student { public string Name { get; set; } }
|
List<Student> students = new List<Student>(); students.Add(new Student() { Name = "测试1" }); students.Add(new Student() { Name = "你好" }); students.Add(new Student() { Name = "abcd" });
BindingOperations.SetBinding(op1, TextBox.TextProperty,new Binding() { Source = students, Path = new PropertyPath("/"),Mode = BindingMode.OneWay }); BindingOperations.SetBinding(op2, TextBox.TextProperty, new Binding() { Source = students, Path = new PropertyPath("/Name"), Mode = BindingMode.OneWay }); BindingOperations.SetBinding(op3, TextBox.TextProperty, new Binding() { Source = students, Path = new PropertyPath("/Name.Length"), Mode = BindingMode.OneWay }); BindingOperations.SetBinding(op4, TextBox.TextProperty, new Binding() { Source = students, Path = new PropertyPath("[1]"), Mode = BindingMode.OneWay }); BindingOperations.SetBinding(op5, TextBox.TextProperty, new Binding() { Source = students, Path = new PropertyPath("[2].Name"), Mode = BindingMode.OneWay });
public class Student { public string Name { get; set; } public override string ToString() { return "Student:[" + Name+"]"; } }
<TextBox x:Name="op1" ></TextBox> <TextBox x:Name="op2" ></TextBox> <TextBox x:Name="op3" ></TextBox> <TextBox x:Name="op4" ></TextBox> <TextBox x:Name="op5" ></TextBox>
|
总结:使用属性名称,点(.),斜杠(/),方括号([1])表达属性。
其中点(.) 表示下级属性,斜杠表示集合的第一个元素,方括号([])表示取集合的第几个元素。
如果整个元数据就是要绑定的对象,则Path使用点(.) 表示,在xaml文法中甚至可以不写。
数据源的来源:
DataContext 每个WPF控件都具有整个属性。当不指定Source,仅仅指定Path的情况下,控件会沿着空间树向上寻找,查看每个节点的DataConetxt属性是否具有指定的Path.
<StackPanel.DataContext> <local:Student Name="王和诺" Age="32" Id="9001"></local:Student> </StackPanel.DataContext>
<TextBox Text="{Binding Path=Name}"></TextBox> <TextBox Text="{Binding Path=Id}"></TextBox>
|
<StackPanel.DataContext> <sys:String>你好</sys:String> </StackPanel.DataContext>
<TextBox Text="{Binding .}"></TextBox>
|
1.当多个控件关联同一个对象时,可以使用DataContext
2.跨窗体传递数据时可以使用DataContext属性,因为控件可能时私有的,但是DataConetxt都是Public的。
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" xmlns:test="clr-namespace:System.Data;assembly=System.Data" xmlns:sys="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <Binding ElementName="text1"/> </Window.DataContext> <Grid> <StackPanel> <TextBox x:Name="text1"></TextBox> <Button Click="text_Click" x:Name="text" Content="测试"></Button> </StackPanel>
</Grid> </Window>
private void text_Click(object sender, RoutedEventArgs e) { Window1 window1 = new Window1(this.DataContext); window1.ShowDialog(); }
|
<TextBox Text="{Binding Path=Text}"></TextBox>
public Window1(object obj) { InitializeComponent(); this.DataContext = obj; }
|
传递多行数据:
<StackPanel> <DataGrid x:Name="dg" AutoGenerateColumns="False" Height="100"> <DataGrid.Columns> <DataGridTextColumn Header="名称1" Binding="{ Binding Name1}"></DataGridTextColumn> <DataGridTextColumn Header="名称2" Binding="{ Binding Name2}"></DataGridTextColumn> <DataGridTextColumn Header="名称3" Binding="{ Binding Name3}"></DataGridTextColumn> </DataGrid.Columns> </DataGrid>
<Button Grid.Row="1" Grid.Column="0" Content="测试" Click="text_Click"></Button> </StackPanel>
public MainWindow() { InitializeComponent();
List<Student> students = new List<Student>();
students.Add(new Student() { Name1 = "90", Name2 = "9003", Name3 = "测试为" });
dg.ItemsSource = students;
}
private void text_Click(object sender, RoutedEventArgs e) {
var obj = dg.SelectedItem; Window1 window1 = new Window1(obj); window1.ShowDialog();
public class Student { public string Name1 { get; set; } public string Name2 { get; set; } public string Name3{ get; set; }
public override string ToString() { return ""; } } |
public Window1(object obj) { InitializeComponent(); this.DataContext = obj; }
<StackPanel>
<TextBox Text="{Binding Path=Name1}"></TextBox> <TextBox Text="{Binding Path=Name2}"></TextBox> <TextBox Text="{Binding Path=Name3}"></TextBox> </StackPanel>
|
Datatable/dataview作为数据源。
相对数据源:RelativeSource
<StackPanel x:Name="text"> <DataGrid x:Name="dg" AutoGenerateColumns="False" Height="100"> <DataGrid.Columns> <DataGridTextColumn Header="名称1" Binding="{ Binding Name1}"></DataGridTextColumn> <DataGridTextColumn Header="名称2" Binding="{ Binding Name2}"></DataGridTextColumn> <DataGridTextColumn Header="名称3" Binding="{ Binding Name3}"></DataGridTextColumn> </DataGrid.Columns> </DataGrid>
<Button Grid.Row="1" Grid.Column="0" Height="40" Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=StackPanel},Path=Name}" Click="text_Click"></Button> </StackPanel>
|
数据校验
Binding binding = new Binding(); binding.Source = s1; binding.Path = new PropertyPath("Value"); binding.ValidationRules.Add(new RangeValidationRule()); binding.NotifyOnValidationError = true; BindingOperations.SetBinding(te, TextBox.TextProperty, binding);
te.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));
void ValidationError(object sender, RoutedEventArgs e) { if (Validation.GetErrors(te).Count > 0) { MessageBox.Show("yc"+Validation.GetErrors(te)[0].ErrorContent.ToString()); } }
<TextBox x:Name="te"></TextBox> <Slider Maximum="100" Margin="5" x:Name="s1"></Slider>
效果: |
数据转换
实现IValueConvert 接口