简要
-
- Binding基础
- Binding源与路径
- 列举Binding的源
Binding基础
从Coding中看Binding的基础。
先定义一个Student类:
public class Student : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;private string name;public string Name{get{return this.name;}set{name = value;if (PropertyChanged != null){this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));}}}}
XAML设计:
后台部分:
public partial class MainWindow : Window{Student stu;public MainWindow(){InitializeComponent();stu = new Student();Binding binding = new Binding();binding.Source = stu;binding.Path = new PropertyPath("Name");BindingOperations.SetBinding(this.textBoxName, TextBox.TextProperty, binding);}private void Button_Click(object sender, RoutedEventArgs e){stu.Name += "LiLin";}}Run:
在这个例子中,binding的源是stu,binding的路径是Name,既UI关心的那个属性。
首先,定义的Student实现了INotifyPropertyChanged接口,并在Name的set中激发PropertyChanged事件,这是为了是Binding机制能自动监听,并会通知Binding目标端的UI现实新的值。
在后台代码中,Binding部分是先声明Binding类型变量并创建实例,然后指定源与路径,最后使用BindingOperations.SetBinding(…)来实现数据源与目标的连接。
实际中,不需要这么麻烦地实现Binding,因为TextBox继承自FrameworkElement,对BindingOperations.SetBinding(…)进行了封装,提供SetBinding方法:
public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding){return BindingOperations.SetBinding(this, dp, binding);}
使用SetBinding可以简化为:
InitializeComponent();stu = new Student();this.textBoxName.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = stu });
Binding的源与路径
Binding的源只要是一个对象,且拥有公开的属性。可以是实现了INotifyPropertyChanged接口的自定义类、控件、集合、XML…
把控件作为Binding的源:
Run:
控制Binding的方向和数据更新触发方式:
控制Binding数据流向的属性是Mode,枚举。可以取值为:TwoWay、OneWay、OnTime、OneWayToSource、Default。
控制数据更新触发方式的属性是UpdateSourceTrigger,类型是UpdateSourceTrigger枚举,可以取值为:PropertyChanged、LostFocus、Explicit和Default。
Binding的路径:
Binding的路径是指示Binding关注的属性。
为Binding指定源的几种方法:
- 把普通的CLR类型单一对象指定为Source:该类型需实现INotifyPropertyChanged接口,并通过属性的Set语句里激发PropertyChanged事件;
- 把普通的CLR集合类型对象指定为源:包含数组、List<T>、ObservableCollection<T>等集合类型;
- 把ADO.NET数据对象指定为源:有DataTable和DataView等对象;
- 使用XmlDataProvider把XML数据指定为Source;
- 把以来对象指定为源;
- 把容器的DataContext指定为源;
- 通过ElementName指定源:用于XAML中;
- 通过Binding的RelativeSource属性相对指定Source:当控件需要关注自己的、自己容器的或者自己内部元素的某个值就需要使用到这个属性;
- 把ObjectDataProvider对象指定为源;
- 把使用LINQ检索得到的数据对象作为源。
使用DataContext作为Binding的源:
DataContext是定义在WPF控件基类FrameworkElement中,因此所有WPF控件都有这个属性。
简单例子:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:BindBasicTest"Title="MainWindow" Height="150" Width="230">
使用集合对象作为列表控件的ItemsSource:
列表控件都是派生自ItemsControl类,则都继承了ItemsSource这个属性。ItemsSource属性可以接受一个IEnumerable接口的派生类。只要为ItemsControl对象设置ItemsSource属性值,ItemsSource就会自动迭代其中的数据。
例子:
XAML设计:
后台代码:
public MainWindow(){InitializeComponent();Liststu_list = new List () {new Student(){Id=0,Name="LiLin",Age=18},new Student(){Id=1,Name="LinLi",Age=20},new Student(){Id=2,Name="LLiin",Age=24},new Student(){Id=3,Name="Tom",Age=27},new Student(){Id=4,Name="Tim",Age=19},new Student(){Id=5,Name="Luke",Age=23},};this.listBoxStudent.ItemsSource = stu_list;this.listBoxStudent.DisplayMemberPath = "Name";this.txtBoxId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.listBoxStudent });}
Run:
this.listBoxStudent.DisplayMemberPath = "Name";这是设置listbox显示字段,如果要显示多个或者全部字段呢。这就要使用到类型为DataTemplate的ItemTemplate属性(继承自ItemsControl类),通俗的说是换衣服。在XAML中修改代码,并把this.listBoxStudent.DisplayMemberPath = "Name";删除:
Run:
注意事项:使用集合对象作为列表控件的ItemsSource时,一般会使用ObservableCollection<T>代替List<T>,理由是,ObservableCollection<T>实现了INotifyCollectionChanged和INotifyPropertyChanged接口。
使用ADO.NET对象作为Binding对象:
在WPF中支持列表控件与DataTable直接建立Binding。假设已经获得了一个DataTable的实例,数据跟以上的一样。现在Coding把它显示在ListBox中:
DataTable dt = Load();this.listBoxStudent.ItemsSource = dt.DefaultView;
Run:
换件“衣服”:
Run:
有点注意的:ListView和GridView不是同一级别的控件。ListView是继承自ListBox,GridView是ViewBase的派生类,ListView的View属性是ViewBase的对象。因此,GridView可以作为ListView的View来使用。
如果想用更复杂的结构来表示标题或者数据,可以为GridViewColumn设置HeaderTemplate和CellTemplate属性,类型都是DataTemplate。
使用XML数据作为Binding的源: 现在程序中涉及到数据传输都离不开XML。XML文本是树形结构,可以方便地用于表示线性集合。
先Coding一个:
有这么一个Student.xml,
LiLin Tom Tim Luke Jake LiLi
XAML:
后台:
XmlDocument xdoc = new XmlDocument();xdoc.Load(@"C:\Student.xml");XmlDataProvider xdp = new XmlDataProvider();xdp.Document = xdoc;xdp.XPath = @"/StudentList/Student";this.listViewStudent.DataContext = xdp;this.listViewStudent.SetBinding(ListView.ItemsSourceProperty, new Binding());注意:XAML中DisplayMemberBinding="{Binding XPath=@Id}"和DisplayMemberBinding="{Binding XPath=Name}"之间的@差异,指明了关注的xml路径不同,使用@表示是XML元素的Attribute,不加的是指子集元素。
使用LINQ检索结果作为Binding的源:
因为LINQ查询结果是一个IEnumerable<T>类型的对象,而IEnumerable<T>继承了IEnumerable,所以它可以作为列表控件的ItemsSource来使用。
Coding:
Liststu_list = new List () {new Student(){Id=0,Name="LiLin",Age=18},new Student(){Id=1,Name="LinLi",Age=20},new Student(){Id=2,Name="LLiin",Age=24},new Student(){Id=3,Name="Tom",Age=27},new Student(){Id=4,Name="Tim",Age=19},new Student(){Id=5,Name="Luke",Age=23},};this.listViewStudent.ItemsSource = from stu in stu_list where stu.Age <= 20 select stu;
使用ObjectDataProvider对象作为Binding的Source:
当我们需要的数据是方法的返回值,而非是一个类型的属性的时候,我们就用到了ObjectDataProvider来Binding。
Coding:
XMAL,
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:BindBasicTest"Title="MainWindow" Height="200" Width="230" Background="LightBlue">
后台:
public MainWindow(){InitializeComponent();SetBinding();}private void SetBinding(){ObjectDataProvider odp = new ObjectDataProvider();odp.ObjectInstance = new Calculate();odp.MethodName = "Add";odp.MethodParameters.Add("0");odp.MethodParameters.Add("0");Binding bindingNum1 = new Binding("MethodParameters[0]"){Source = odp,BindsDirectlyToSource = true,UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,};Binding bindingNum2 = new Binding("MethodParameters[1]"){Source = odp,BindsDirectlyToSource = true,UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,};Binding bindingReslut = new Binding(".") { Source = odp };this.textBoxArg1.SetBinding(TextBox.TextProperty,bindingNum1);this.textBoxArg2.SetBinding(TextBox.TextProperty, bindingNum2);this.textBoxResult.SetBinding(TextBox.TextProperty, bindingReslut);}
RUN:
Binding的RelativeSource属性相对指定Source:
当不能确定source对象的名字,但知道它与作为Binding目标的对象在UI布局上的关系时候,我们可以用Binding的RelativeSource属性。
Coding:
XAML,
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:BindBasicTest"Title="MainWindow" Height="200" Width="230" Background="LightBlue">
后台:
InitializeComponent();RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor);rs.AncestorLevel = 1;rs.AncestorType = typeof(Grid);Binding binding = new Binding("Name") { RelativeSource = rs };this.textBox.SetBinding(TextBox.TextProperty, binding);
RUN: