一般情况下,应用程序会有三层结构:数据存储层,数据处理层(业务逻辑层),数据展示层(UI界面)。
WPF是“数据驱动UI”。
- Binding实现(通过纯C#代码)
Binding分为source和target,即源和目标。
如何通过Binging实现UI元素和代码对象的连接。
首先绑定源对象要实现INotifyPropertyChanged接口,该接口引用自System.ComponentModel命名空间,所有使用前要引用该命名空间。该接口有一个PropertyChanged事件,可以帮助自动监听源对象的属性变化。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents; 10 using System.Windows.Input; 11 using System.Windows.Media; 12 using System.Windows.Media.Imaging; 13 using System.Windows.Navigation; 14 using System.Windows.Shapes; 15 using System.ComponentModel; 16 class Student:INotifyPropertyChanged 17 { 18 public event PropertyChangedEventHandler PropertyChanged; 19 private string name; 20 21 public string Name 22 { 23 get { return name; } 24 set { 25 name = value; 26 if(this.PropertyChanged!=null) 27 { 28 this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); 29 } 30 } 31 } 32 33 34 }
如上代码所示,在绑定了接口以后,当Name属性的值发生变化时,就会自动通知,然后刷新UI元素进行更新。
当然还没有结束,我们现在需要添加界面。然后在后台代码中设置Binding
其实在textBox元素中已经为我们封装好了这些,即SetBinding方法。
所以可以改写如下:
- 标记扩展进行Data Binding
- 控制Binding数据流向的是Mode属性,而控制数据更新的是UpdateSourceTrigger属性
- 没有Path的Binding
有时候,Binding源本身就是数据,比如字符串,或者int类型,他们的实例本身就是数据,而不需要通过属性来提供访问,那么在指定path时可以通过一个.来代替,或者直接不写path,在XAML代码里可以省略不写,在C#代码中必须显式写.来表示path指向实例本身。
- 为Binding指定源的几种方法
- Binding过程中可以没有path,那么可不可以没有source,当然可以,可以通过添加DataContext来隐式表达source。
- 使用集合对象作为列表控件的ItemsSource
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents; 10 using System.Windows.Input; 11 using System.Windows.Media; 12 using System.Windows.Media.Imaging; 13 using System.Windows.Navigation; 14 using System.Windows.Shapes; 15 using System.ComponentModel; 16 17 namespace WpfApp7 18 { 19 /// <summary> 20 /// MainWindow.xaml 的交互逻辑 21 /// </summary> 22 public partial class MainWindow : Window 23 { 24 public MainWindow() 25 { 26 InitializeComponent(); 27 28 //准备数据源 29 List<Student> stuList = new List<Student>() 30 { 31 new Student(){Id=0,Name="Tim",Age=29}, 32 new Student(){Id=1,Name="Tom",Age=28}, 33 new Student(){Id=2,Name="Kyle",Age=27}, 34 new Student(){Id=3,Name="Tony",Age=26}, 35 new Student(){Id=4,Name="Vina",Age=25}, 36 }; 37 //为listBox设置Binding 38 this.listBoxStudents.ItemsSource = stuList; 39 this.listBoxStudents.DisplayMemberPath = "Name"; 40 //为TextBox设置Binding 41 Binding binding = new Binding("SelectedItem.Id") { Source = this.listBoxStudents }; 42 this.textBoxId.SetBinding(TextBox.TextProperty, binding); 43 } 44 } 45 46 class Student 47 { 48 public int Id { get; set; } 49 public string Name { get; set; } 50 public int Age { get; set; } 51 52 } 53 54 }
界面代码如下:
<Window x:Class="WpfApp7.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:WpfApp7" mc:Ignorable="d" Title="Binding Source" Height="240" Width="300"> <StackPanel x:Name="stackPanel1" 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> </Window>
- 使用ObjectDataProvider对象作为Binding的Source
现在有一个Calculator的类,他具有加减乘除的方法:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents; 10 using System.Windows.Input; 11 using System.Windows.Media; 12 using System.Windows.Media.Imaging; 13 using System.Windows.Navigation; 14 using System.Windows.Shapes; 15 16 namespace ObjectDateProvider 17 { 18 /// <summary> 19 /// MainWindow.xaml 的交互逻辑 20 /// </summary> 21 public partial class MainWindow : Window 22 { 23 public MainWindow() 24 { 25 InitializeComponent(); 26 this.SetBinding(); 27 } 28 29 30 private void SetBinding() 31 { 32 //创建并配置ObjectDataProvider对象 33 ObjectDataProvider odp = new ObjectDataProvider 34 { 35 ObjectInstance = new Calculator(), 36 MethodName = "Add" 37 }; 38 odp.MethodParameters.Add("0"); 39 odp.MethodParameters.Add("0"); 40 //以ObjectDataProvider对象为Source创建Binding 41 Binding bindingToArg1 = new Binding("MethodParameters[0]") 42 { 43 Source = odp, 44 BindsDirectlyToSource = true, 45 UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged 46 }; 47 Binding bindingToArg2 = new Binding("MethodParameters[1]") 48 { 49 Source = odp, 50 BindsDirectlyToSource = true, 51 UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged 52 }; 53 54 Binding bindingToResult = new Binding(".") { Source = odp }; 55 56 //将Binding关联到UI元素上 57 this.textBoxArg1.SetBinding(TextBox.TextProperty, bindingToArg1); 58 this.textBoxArg2.SetBinding(TextBox.TextProperty, bindingToArg2); 59 this.textBoxResult.SetBinding(TextBox.TextProperty, bindingToResult); 60 } 61 } 62 63 class Calculator 64 { 65 public string Add(string arg1,string arg2) 66 { 67 double x = 0; 68 double y = 0; 69 double z = 0; 70 if(double.TryParse(arg1,out x)&&double.TryParse(arg2,out y)) 71 { 72 z = x + y; 73 return z.ToString(); 74 } 75 return "Input Error"; 76 } 77 } 78 }
界面代码如下:
1 <Window x:Class="ObjectDateProvider.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:ObjectDateProvider" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="135" Width="300"> 9 <StackPanel Background="LightBlue"> 10 <TextBox x:Name="textBoxArg1" Margin="5"/> 11 <TextBox x:Name="textBoxArg2" Margin="5"/> 12 <TextBox x:Name="textBoxResult" Margin="5"/> 13 14 </StackPanel> 15 </Window>
- 使用Binding的RelativeSource
- Binding对数据的转换与校验
Binding用于数据有效性检验的是ValidationRules属性,用于数据类型转换关卡的是Converter属性。