首页 > 代码库 > 0001 WindowsForms的数据绑定(基础)

0001 WindowsForms的数据绑定(基础)

一、数据绑定原理
创建一个简单的数据绑定引擎:
二、简单数据绑定和项数据源
三、简单绑定和列表数据源
四、复杂绑定和列表数据源
五、IBindingList接口 和 BindingList类
六、BindingSource (System.Window.Forms.BindingSource)
将项类型转变为列表数据源

一、数据绑定原理

逻辑上,数据绑定“对象属性”“控件属性”之间的关联,这种关联是由数据绑定引擎完成的。
当对象属性和控件属性其中之一发生变化时,就会自动更新另一方的数据。

创建一个简单的数据绑定引擎:

定义一个数据源RaceCarDriver.cs,实现接口System.ComponentModel.INotifyPropertyChanged。

  1. using System.ComponentModel;
  2. namespace BasicBindingEngine
  3. {
  4. class RaceCarDriver : INotifyPropertyChanged
  5. {
  6. //实现接口INotifyPropertyChanged
  7. public event PropertyChangedEventHandler PropertyChanged;
  8. void OnPropertyChanged(string propertyName)
  9. {
  10. if (this.PropertyChanged != null)
  11. {
  12. this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  13. }
  14. }
  15. string name;
  16. int wins;
  17. public RaceCarDriver(string name, int wins)
  18. {
  19. this.name = name;
  20. this.wins = wins;
  21. }
  22. public string Name
  23. {
  24. get { return name; }
  25. set
  26. {
  27. name = value;
  28. //提供被修改的属性名称
  29. OnPropertyChanged("Name");
  30. }
  31. }
  32. public int Wins
  33. {
  34. get { return wins; }
  35. set
  36. {
  37. wins = value;
  38. OnPropertyChanged("Wins");
  39. }
  40. }
  41. }
  42. }

技术分享
窗体代码,实现数据绑定。

  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows.Forms;
  4. namespace BasicBindingEngine
  5. {
  6. public partial class Form1 : Form
  7. {
  8. RaceCarDriver raceCarDriver = new RaceCarDriver("M Schumacher", 500);
  9. public Form1()
  10. {
  11. InitializeComponent();
  12. //将初始的RaceCarDriver状态复制到文本框控件
  13. this.nameText.Text = this.raceCarDriver.Name;
  14. this.winsText.Text = this.raceCarDriver.Wins.ToString();
  15. //数据绑定,双向检测
  16. //检测文本框控件的修改,更新数据源数据
  17. this.nameText.TextChanged += NameText_TextChanged;
  18. this.winsText.TextChanged += WinsText_TextChanged;
  19. //检测RaceCarDriver对象的修改,更新文本框数据显示
  20. this.raceCarDriver.PropertyChanged += RaceCarDriver_PropertyChanged;
  21. }
  22. private void WinsText_TextChanged(object sender, EventArgs e)
  23. {
  24. this.raceCarDriver.Wins = int.Parse(this.winsText.Text);
  25. }
  26. private void NameText_TextChanged(object sender, EventArgs e)
  27. {
  28. this.raceCarDriver.Name = this.nameText.Text;
  29. }
  30. //直接修改RaceCarDriver的wins数据
  31. private void AddWinBtn_Click(object sender, EventArgs e)
  32. {
  33. ++this.raceCarDriver.Wins;
  34. }
  35. private void RaceCarDriver_PropertyChanged(object sender, PropertyChangedEventArgs e)
  36. {
  37. switch (e.PropertyName)
  38. {
  39. case "Name":
  40. this.nameText.Text = this.raceCarDriver.Name;
  41. break;
  42. case "Wins":
  43. this.winsText.Text = this.raceCarDriver.Wins.ToString();
  44. break;
  45. }
  46. }
  47. }
  48. }

二、简单数据绑定和项数据源

Windows Forms 数据绑定引擎的基本生成块就是Binding对象,它将控件数据绑定到对象属性上。

简单绑定:将控件属性绑定到对象属性的操作叫做简单绑定

项数据源:数据源的数据是存在于单个项中。例如RaceCarDriver这样的绑定对象。

绑定关系类System.Windows.Forms.Binding,通过此可以省却写属性检测代码。

  1. public Binding(string propertyName, object dataSource, string dataMember);
  2. propertyName: 要绑定的控件属性的名称。
  3. dataSource: 一个 System.Object,它代表数据源。
  4. dataMember: 要绑定到的属性或列表。

窗体代码,通过Binding实现数据绑定。控件的DataBindings添加绑定关系。

  1. using System;
  2. using System.Windows.Forms;
  3. namespace BasicBindingEngine
  4. {
  5. public partial class Form1 : Form
  6. {
  7. RaceCarDriver raceCarDriver = new RaceCarDriver("M Schumacher", 500);
  8. public Form1()
  9. {
  10. InitializeComponent();
  11. //将Name和Wins属性绑定到Name和Wins文本框上
  12. Binding nameBinding = new Binding("Text", this.raceCarDriver, "Name", true);
  13. this.nameText.DataBindings.Add(nameBinding);
  14. Binding winsBinding = new Binding("Text", this.raceCarDriver, "Wins", true);
  15. this.winsText.DataBindings.Add(winsBinding);
  16. }
  17. //直接修改RaceCarDriver的wins数据
  18. private void AddWinBtn_Click(object sender, EventArgs e)
  19. {
  20. ++this.raceCarDriver.Wins;
  21. }
  22. }
  23. }

添加绑定时会发生两件事情:1.数据绑定引擎自动使用对象属性的值来填充控件的属性。2.任何必需的数据转换都自动完成。

初始化之后,数据绑定引擎负责控件属性和数据源对象属性之间的同步。为了确保数据的变化可以从对象复制到控件上,绑定引擎会查找INotifyPropertyChanged.PropertyChanged事件。

只有在对象触发INotifyPropertyChanged.PropertyChanged事件并且公共属性是可读写(实现了get,set访问器)的情况下,简单绑定才是双向的。

三、简单绑定和列表数据源

列表数据源:是在绑定操作中作为数据来使用的同构对象的集合。对象是必须实现‘ IList ‘接口的类。

绑定管理器:负责管理特定数据源的绑定集合,有两个方面的作用:属性管理器当前项管理器。两个管理器都是由抽象基类BindingManagerBase的具体实现。

属性管理器:是PropertyManager类的一个实例,并且是为项数据源创建的。

当前项管理器:是CurrencyManager类的一个实例,并且是为列表数据源来创建的。可用于跟踪当前对象的位置。

技术分享

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows.Forms;
  4. namespace SimpleBindingAndListDataSource
  5. {
  6. public partial class SBALDS : Form
  7. {
  8. //创建强类型数据列表数据源
  9. List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>();
  10. public SBALDS()
  11. {
  12. InitializeComponent();
  13. //用数据项填充列表数据源
  14. this.raceCarDrivers.Add(new RaceCarDriver("M.Schumacher", 500));
  15. this.raceCarDrivers.Add(new RaceCarDriver("A.Senna", 1000));
  16. this.raceCarDrivers.Add(new RaceCarDriver("A.Prost", 400));
  17. //将Name和Wins属性绑定到Name和Wins文本框上
  18. this.nameTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Name");
  19. this.winsTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Wins");
  20. RefreshShowMangerPositon();
  21. }
  22. BindingManagerBase BindingManager
  23. {
  24. //访问RaceCarDriver列表数据源的绑定管理器
  25. get { return this.BindingContext[this.raceCarDrivers]; }
  26. }
  27. private void MoveFirstBtn_Click(object sender, EventArgs e)
  28. {
  29. this.BindingManager.Position = 0;
  30. RefreshShowMangerPositon();
  31. }
  32. private void MovePreviousBtn_Click(object sender, EventArgs e)
  33. {
  34. --this.BindingManager.Position;
  35. RefreshShowMangerPositon();
  36. }
  37. private void MoveNextBtn_Click(object sender, EventArgs e)
  38. {
  39. ++this.BindingManager.Position;
  40. RefreshShowMangerPositon();
  41. }
  42. private void MoveLastBtn_Click(object sender, EventArgs e)
  43. {
  44. this.BindingManager.Position = this.BindingManager.Count - 1;
  45. RefreshShowMangerPositon();
  46. }
  47. void RefreshShowMangerPositon()
  48. {
  49. int count = this.BindingManager.Count;
  50. int position = this.BindingManager.Position + 1;
  51. this.bindingNavigatorPositionItem.Text = position.ToString();
  52. this.bindingNavigatorCountItem.Text = string.Format("/{0}", count);
  53. this.bindingNavigatorMoveFirstItem.Enabled = (position > 1);
  54. this.bindingNavigatorMovePreviousItem.Enabled = (position > 1);
  55. this.bindingNavigatorMoveNextItem.Enabled = (position < count);
  56. this.bindingNavigatorMoveLastItem.Enabled = (position < count);
  57. }
  58. }
  59. }

使用这种方式时,简单绑定和列表数据源中在添加绑定时没有实现事件event PropertyChangedEventHandler PropertyChanged,导致在修改数据源属性时不能更新控件属性。使用IBindingList接口解决这种问题。

四、复杂绑定和列表数据源

复杂绑定:将控件的一个属性绑定到整个列表数据源中。复杂绑定中的复杂是指控件自身内置的对操作和输出列表数据的附加支持。

复杂控件使用DataSource属性访问列表数据源,使用DisplayMember设置需要显示的列表数据源属性

  1. ...引用
  2. namespace ComplexBindingListDataSources
  3. {
  4. public partial class Form1 : Form
  5. {
  6. //创建强类型列表数据源
  7. List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>();
  8. public Form1()
  9. {
  10. InitializeComponent();
  11. this.raceCarDrivers.Add(new RaceCarDriver("M.Schuamacher", 500));
  12. this.raceCarDrivers.Add(new RaceCarDriver("A.Senna", 1000));
  13. this.raceCarDrivers.Add(new RaceCarDriver("A.Prost", 400));
  14. //将Name和Wins属性简单绑定到Name和Wins文本框
  15. //当用户输入数据时保持对象属性的同步
  16. this.nameTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Name");
  17. this.winTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Wins");
  18. //复杂绑定列表框到RaceCarDriver列表数据源
  19. this.raceCarDriverListBox.DataSource = this.raceCarDrivers;
  20. //指定列表数据源中的项出现在列表框中的属性
  21. this.raceCarDriverListBox.DisplayMember = "Name";
  22. this.raceCarDriversDataGridView.DataSource = this.raceCarDrivers;
  23. RefreshShowMangerPositon();
  24. }
  25. ....
  26. 导航相关代码
  27. ....
  28. }
  29. }

技术分享

五、IBindingList接口 和 BindingList

在绑定中,对列表数据源的修改不会立即显示在界面上。这就需要实现一个通信协议让控件能够知道列表数据源的变化。通过实现接口IBindingList来实现通知。

IBindingList:是关于数据绑定架构的约定,扩展了IList接口,增加了为列表数据源提供的数据绑定特定的功能。实现添加、更新、删除列表数据源项。支持列表修改通知功能,通过订阅ListChanged事件。

System.ComponentModel.BindingList:是IBindingList接口的泛型实现。实现了列表管理功能(AllowEdit、AllowNew、AllowRemove、AddNew)和 实现IBindingList的变更通知功能的子集(SupportsChangeNotification、ListChanged)。

List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>();改写为BindingList<RaceCarDriver> raceCarDrivers = new BindingList<RaceCarDriver>();就实现了列表数据源变更时通知功能。

  1. class RaceCarDriver : INotifyPropertyChanged
  2. {
  3. //要让DataGridView可以添加新行,就需要这个构造函数
  4. public RaceCarDriver()
  5. {
  6. }
  7. ....
  8. }

技术分享

六、BindingSource (System.Window.Forms.BindingSource)

通过BindingSource类可将现存的IList升级到IBindingList。

将项类型转变为列表数据源

  1. //创建强类型数据列表数据源
  2. List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>();
  3. BindingSource raceCarDriversBS = new BindingSource();
  4. public SBALDS()
  5. {
  6. InitializeComponent();
  7. //用数据项填充列表数据源
  8. this.raceCarDrivers.Add(new RaceCarDriver("M.Schumacher", 500));
  9. this.raceCarDrivers.Add(new RaceCarDriver("A.Senna", 1000));
  10. this.raceCarDrivers.Add(new RaceCarDriver("A.Prost", 400));
  11. //给List<RaceCarDriver>加上列表管理和变更通知功能
  12. raceCarDriversBS.DataSource = this.raceCarDrivers;
  13. //将数据源变为this.raceCarDriversBS
  14. this.nameTextBox.DataBindings.Add("Text", this.raceCarDriversBS, "Name");
  15. this.winsTextBox.DataBindings.Add("Text", this.raceCarDriversBS, "Wins");
  16. ...
  17. }

0001 WindowsForms的数据绑定(基础)