邏輯上,數據綁定是「對象屬性」和「控件屬性」之間的關聯,這種關聯是由數據綁定引擎完成的。
當對象屬性和控件屬性其中之一發生變化時,就會自動更新另外一方的數據。c#
定義一個數據源RaceCarDriver.cs,實現接口System.ComponentModel.INotifyPropertyChanged。架構
using System.ComponentModel;namespace BasicBindingEngine{ class RaceCarDriver : INotifyPropertyChanged { //實現接口INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } string name; int wins; public RaceCarDriver(string name, int wins) { this.name = name; this.wins = wins; } public string Name { get { return name; } set { name = value; //提供被修改的屬性名稱 OnPropertyChanged("Name"); } } public int Wins { get { return wins; } set { wins = value; OnPropertyChanged("Wins"); } } }}
窗體代碼,實現數據綁定。函數
using System;using System.ComponentModel;using System.Windows.Forms;namespace BasicBindingEngine{ public partial class Form1 : Form { RaceCarDriver raceCarDriver = new RaceCarDriver("M Schumacher", 500); public Form1() { InitializeComponent(); //將初始的RaceCarDriver狀態複製到文本框控件 this.nameText.Text = this.raceCarDriver.Name; this.winsText.Text = this.raceCarDriver.Wins.ToString(); //數據綁定,雙向檢測 //檢測文本框控件的修改,更新數據源數據 this.nameText.TextChanged += NameText_TextChanged; this.winsText.TextChanged += WinsText_TextChanged; //檢測RaceCarDriver對象的修改,更新文本框數據顯示 this.raceCarDriver.PropertyChanged += RaceCarDriver_PropertyChanged; } private void WinsText_TextChanged(object sender, EventArgs e) { this.raceCarDriver.Wins = int.Parse(this.winsText.Text); } private void NameText_TextChanged(object sender, EventArgs e) { this.raceCarDriver.Name = this.nameText.Text; } //直接修改RaceCarDriver的wins數據 private void AddWinBtn_Click(object sender, EventArgs e) { ++this.raceCarDriver.Wins; } private void RaceCarDriver_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { case "Name": this.nameText.Text = this.raceCarDriver.Name; break; case "Wins": this.winsText.Text = this.raceCarDriver.Wins.ToString(); break; } } }}
Windows Forms 數據綁定引擎的基本生成塊就是Binding對象,它將控件數據綁定到對象屬性上。 this
簡單綁定:將控件屬性綁定到對象屬性的操做叫作簡單綁定。 spa
項數據源:數據源的數據是存在於單個項中。例如RaceCarDriver這樣的綁定對象。code
綁定關係類System.Windows.Forms.Binding
,經過此能夠省卻寫屬性檢測代碼。orm
public Binding(string propertyName, object dataSource, string dataMember); propertyName: 要綁定的控件屬性的名稱。 dataSource: 一個 System.Object,它表明數據源。 dataMember: 要綁定到的屬性或列表。
窗體代碼,經過Binding實現數據綁定。控件的DataBindings添加綁定關係。對象
using System;using System.Windows.Forms;namespace BasicBindingEngine{ public partial class Form1 : Form { RaceCarDriver raceCarDriver = new RaceCarDriver("M Schumacher", 500); public Form1() { InitializeComponent(); //將Name和Wins屬性綁定到Name和Wins文本框上 Binding nameBinding = new Binding("Text", this.raceCarDriver, "Name", true); this.nameText.DataBindings.Add(nameBinding); Binding winsBinding = new Binding("Text", this.raceCarDriver, "Wins", true); this.winsText.DataBindings.Add(winsBinding); } //直接修改RaceCarDriver的wins數據 private void AddWinBtn_Click(object sender, EventArgs e) { ++this.raceCarDriver.Wins; } }}
添加綁定時會發生兩件事情:1.數據綁定引擎自動使用對象屬性的值來填充控件的屬性。2.任何須需的數據轉換都自動完成。blog
初始化以後,數據綁定引擎負責控件屬性和數據源對象屬性之間的同步。爲了確保數據的變化能夠從對象複製到控件上,綁定引擎會查找INotifyPropertyChanged.PropertyChanged事件。接口
只有在對象觸發INotifyPropertyChanged.PropertyChanged事件而且公共屬性是可讀寫(實現了get,set訪問器)的狀況下,簡單綁定纔是雙向的。
列表數據源:是在綁定操做中做爲數據來使用的同構對象的集合。對象是必須實現' IList '接口的類。
綁定管理器:負責管理特定數據源的綁定集合,有兩個方面的做用:屬性管理器和當前項管理器。兩個管理器都是由抽象基類BindingManagerBase的具體實現。
屬性管理器:是PropertyManager類的一個實例,而且是爲項數據源建立的。
當前項管理器:是CurrencyManager類的一個實例,而且是爲列表數據源來建立的。可用於跟蹤當前對象的位置。
using System;using System.Collections.Generic;using System.Windows.Forms;namespace SimpleBindingAndListDataSource{ public partial class SBALDS : Form { //建立強類型數據列表數據源 List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>(); public SBALDS() { InitializeComponent(); //用數據項填充列表數據源 this.raceCarDrivers.Add(new RaceCarDriver("M.Schumacher", 500)); this.raceCarDrivers.Add(new RaceCarDriver("A.Senna", 1000)); this.raceCarDrivers.Add(new RaceCarDriver("A.Prost", 400)); //將Name和Wins屬性綁定到Name和Wins文本框上 this.nameTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Name"); this.winsTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Wins"); RefreshShowMangerPositon(); } BindingManagerBase BindingManager { //訪問RaceCarDriver列表數據源的綁定管理器 get { return this.BindingContext[this.raceCarDrivers]; } } private void MoveFirstBtn_Click(object sender, EventArgs e) { this.BindingManager.Position = 0; RefreshShowMangerPositon(); } private void MovePreviousBtn_Click(object sender, EventArgs e) { --this.BindingManager.Position; RefreshShowMangerPositon(); } private void MoveNextBtn_Click(object sender, EventArgs e) { ++this.BindingManager.Position; RefreshShowMangerPositon(); } private void MoveLastBtn_Click(object sender, EventArgs e) { this.BindingManager.Position = this.BindingManager.Count - 1; RefreshShowMangerPositon(); } void RefreshShowMangerPositon() { int count = this.BindingManager.Count; int position = this.BindingManager.Position + 1; this.bindingNavigatorPositionItem.Text = position.ToString(); this.bindingNavigatorCountItem.Text = string.Format("/{0}", count); this.bindingNavigatorMoveFirstItem.Enabled = (position > 1); this.bindingNavigatorMovePreviousItem.Enabled = (position > 1); this.bindingNavigatorMoveNextItem.Enabled = (position < count); this.bindingNavigatorMoveLastItem.Enabled = (position < count); } }}
使用這種方式時,簡單綁定和列表數據源中在添加綁定時沒有實現事件event PropertyChangedEventHandler PropertyChanged
,致使在修改數據源屬性時不能更新控件屬性。使用IBindingList
接口解決這種問題。
複雜綁定:將控件的一個屬性綁定到整個列表數據源中。複雜綁定中的複雜是指控件自身內置的對操做和輸出列表數據的附加支持。
複雜控件使用DataSource
屬性訪問列表數據源,使用DisplayMember
設置須要顯示的列表數據源屬性
...引用namespace ComplexBindingListDataSources{ public partial class Form1 : Form { //建立強類型列表數據源 List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>(); public Form1() { InitializeComponent(); this.raceCarDrivers.Add(new RaceCarDriver("M.Schuamacher", 500)); this.raceCarDrivers.Add(new RaceCarDriver("A.Senna", 1000)); this.raceCarDrivers.Add(new RaceCarDriver("A.Prost", 400)); //將Name和Wins屬性簡單綁定到Name和Wins文本框 //當用戶輸入數據時保持對象屬性的同步 this.nameTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Name"); this.winTextBox.DataBindings.Add("Text", this.raceCarDrivers, "Wins"); //複雜綁定列表框到RaceCarDriver列表數據源 this.raceCarDriverListBox.DataSource = this.raceCarDrivers; //指定列表數據源中的項出如今列表框中的屬性 this.raceCarDriverListBox.DisplayMember = "Name"; this.raceCarDriversDataGridView.DataSource = this.raceCarDrivers; RefreshShowMangerPositon(); } .... 導航相關代碼 .... }}
在綁定中,對列表數據源的修改不會當即顯示在界面上。這就須要實現一個通訊協議讓控件可以知道列表數據源的變化。經過實現接口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>();
就實現了列表數據源變動時通知功能。
class RaceCarDriver : INotifyPropertyChanged{ //要讓DataGridView能夠添加新行,就須要這個構造函數 public RaceCarDriver() { } ....}
經過BindingSource類可將現存的IList升級到IBindingList。
//建立強類型數據列表數據源List<RaceCarDriver> raceCarDrivers = new List<RaceCarDriver>();BindingSource raceCarDriversBS = new BindingSource();public SBALDS(){ InitializeComponent(); //用數據項填充列表數據源 this.raceCarDrivers.Add(new RaceCarDriver("M.Schumacher", 500)); this.raceCarDrivers.Add(new RaceCarDriver("A.Senna", 1000)); this.raceCarDrivers.Add(new RaceCarDriver("A.Prost", 400)); //給List<RaceCarDriver>加上列表管理和變動通知功能 raceCarDriversBS.DataSource = this.raceCarDrivers; //將數據源變爲this.raceCarDriversBS this.nameTextBox.DataBindings.Add("Text", this.raceCarDriversBS, "Name"); this.winsTextBox.DataBindings.Add("Text", this.raceCarDriversBS, "Wins"); ...}