Binding作为数据的桥梁,连通业务逻辑层的对象(源对象)和UI的控件对象(目标对象)。在这座桥梁上,我们不仅可以控制在源对象与目标对象是双向通行还是单向通行。还可以控制数据的放行时机,甚至可以在这座桥上搭建一些关卡用来转换数据类型或者检验数据的正确性
我们先做一个最基本的例子,
创建一个"Student"类,这个类的实例将作为数据源来使用
public class Student { private int _id; public int ID { get { return _id; } set { _id = value; } } private string _name; public string Name { get { return _name; } set { _name = value; } } private int _age; public int Age { get { return _age; } set { _age = value; } } }
然后我们编写我们的控件对象和创建逻辑对象
<StackPanel Name="stack1"> <TextBox Width="120" Text="{Binding Path=ID}" HorizontalAlignment="Left" Name="txt_ID"></TextBox> <TextBox Width="120" Text="{Binding Path=Name}" HorizontalAlignment="Left" Name="txt_Name" ></TextBox> <TextBox Text="{Binding Path=Age}" Width="120" HorizontalAlignment="Left" Name="txt_Age"></TextBox> </StackPanel>
public Student Stu; public MainWindow() { InitializeComponent(); Stu = new Student { ID = 1, Name = "狗娃", Age = 11 };
//设置元素数据绑定对象 stack1.DataContext = Stu; }
我们可以看到TextBox控件的Text是一个{Binding} 这就是数据绑定的关键字。然后Path属性是需要绑定的属性,然后我们运行就可以看到我们已经绑定OK。
上面我们是使用的界面进行绑定,其实我们还可以使用代码对每一个控件进行绑定。现在我们将WPF界面中的绑定删除掉
<StackPanel Name="stack1"> <TextBox Width="120" HorizontalAlignment="Left" Name="txt_ID"></TextBox> <TextBox Width="120" HorizontalAlignment="Left" Name="txt_Name" ></TextBox> <TextBox Width="120" HorizontalAlignment="Left" Name="txt_Age"></TextBox> </StackPanel>
然后我们使用代码来进行控件绑定
public Student Stu; public MainWindow() { InitializeComponent(); Stu = new Student { ID = 1, Name = "狗娃", Age = 11 }; //创建Binding对象. Binding bindingID = new Binding() {Path = new PropertyPath("ID"),Source=Stu }; //Binding构造参数可以直接传入Path参数 Binding bindingName = new Binding("Name") { Source = Stu }; Binding bindingAge = new Binding("Age") { Source = Stu }; //进行控件绑定(第一个参数是将绑定到哪个属性,第二个参数是绑定对象) this.txt_ID.SetBinding(TextBox.TextProperty, bindingID); this.txt_Name.SetBinding(TextBox.TextProperty, bindingName); this.txt_Age.SetBinding(TextBox.TextProperty,bindingAge); }
可以看到使用代码绑定需要创建Binding对象,然后使用控件的SetBinding方法进行绑定,但是郁闷的我们为了绑定这三个属性要写这么多的代码.所以使用哪种方式绑定看需求来使用.
接下来我们看双向绑定,其实上面那个我们已经实现了双向绑定,我们先做一个例子测试
创建一个测试TextBox并绑定数据ID
<TextBox Width="120" HorizontalAlignment="Left" Name="txt_IDTest"></TextBox>
Binding bindingTestID = new Binding() { Path = new PropertyPath("ID"), Source = Stu };
this.txt_IDTest.SetBinding(TextBox.TextProperty, bindingTestID);
然后我们在更改txt_ID属性值后光标离开就可以看到txt_IDTest的值也随之改变了。这是因为TextBox默认是双向绑定的,所以可以改变,但是如果我们不是使用控件改变的值呢,接下来做个这样例子.在界面上添加一个Button按钮,并添加点击事件
<Button Content="Button" Width="120" HorizontalAlignment="Left" Click="Button_Click"/>
private void Button_Click(object sender, RoutedEventArgs e) { Stu.ID++; }
我们在点击事件中只做了一件事,那就是让Stu的编号加1,但是运行会发现并没有改变。那么该怎么做呢。
我们需要在绑定源类型(Student类型)实现INotifyPropertyChanged接口
public class Student:INotifyPropertyChanged { private int _id; public int ID { get { return _id; } set { _id = value; MyPropertyChanged(nameof(ID)); } } private string _name; public string Name { get { return _name; } set { _name = value; MyPropertyChanged(nameof(Name)); } } private int _age; public event PropertyChangedEventHandler PropertyChanged; public int Age { get { return _age; } set { _age = value; MyPropertyChanged(nameof(Age)); } } private void MyPropertyChanged(string name) { if(PropertyChanged!=null) PropertyChanged(this, new PropertyChangedEventArgs(name)); } }
然后此时我们就可以实现改变了.
2.绑定更新的计时
但是我们往往需要在输入后就让它立即改变,所以我们需要设置Binding对象中的UpdateSourceTrigger属性,
Binding bindingID = new Binding() { Path = new PropertyPath("ID"), Source = Stu, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged};
UpdateSourceTrigger枚举值有4个
- Default:绑定目标属性的默认值
- PropertyChanged:每当绑定目标属性发生改变时,都会更新数据源
- LostFocus:每当绑定目标元素失去焦点时,都会更新绑定源
- Explicit:仅在调用System.Windows.Data.BindingExpression.UpdateSource 方法时更新绑定源。
因此我们将UpdateSourceTrigger的属性值改成PropertyChanged即可
3.设置单项和双向绑定
刚才使用了TextBox的双向绑定,但是比如我们现在不需要双向绑定,我们只需设置Mode属性即可
Binding bindingID = new Binding() { Path = new PropertyPath("ID"), Source = Stu,Mode = BindingMode.OneTime, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged};
BindingMode枚举有5个值
- TwoWay:导致更新源属性或目标属性时自动更新另一方
- OneWay:在更改绑定源(源)时更新绑定目标(目标),如果绑定的控件为隐式只读,则此类型的绑定适用。如果无需监视目标属性的更改 则使用 System.Windows.Data.BindingMode.OneWay 绑定模式可避免 System.Windows.Data.BindingMode.TwoWay
绑定模式的系统开销。
- OneTime:这是实质上是 System.Windows.Data.BindingMode.OneWay 绑定的一种简化形式,它在源值不更改的情况下提供更好的性能。
- OneWayToSource:在目标属性更改时,更新源属性。
- Default: 使用绑定目标的默认 System.Windows.Data.Binding.Mode 值