日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

基于BindingSource的WinForm开发

發(fā)布時(shí)間:2025/3/21 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于BindingSource的WinForm开发 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.引言

BindingSource組件是數(shù)據(jù)源和控件間的一座橋,同時(shí)提供了大量的API和Event供我們使用。使用這些API我們可以將Code與各種具體類型數(shù)據(jù)源進(jìn)行解耦;使用這些Event我們可以洞察數(shù)據(jù)的變化。

2.簡(jiǎn)單綁定

DataTable myTable = myTableAdapter.GetData();//創(chuàng)建Table

BindingSource myBindingSource= new BindingSource();//創(chuàng)建BindingSource

DataGridView myGrid = new DataGridView();//創(chuàng)建GridView

myGrid.DataSource = myBindingSource;//將BindingSource綁定到GridView

myTable;//綁定數(shù)據(jù)到BindingSource

注:

1)綁定到DataTable,其實(shí)是綁定到DataTable提供的DataView上。每個(gè)DataTable都有一個(gè)缺省的DataView

2)DataView是綁定的實(shí)質(zhì),正如其名,它是DataTable的數(shù)據(jù)的展現(xiàn)。因此可以對(duì)同一個(gè)DataTable

,構(gòu)建多個(gè)DataView,進(jìn)而可以對(duì)這同樣的數(shù)據(jù)實(shí)施不同的過(guò)濾、排序等方法,從不同側(cè)面展示DataTable。這也體現(xiàn)了一定的MVC思想。

3)BindingSouce也可作為數(shù)據(jù)(其實(shí)是數(shù)據(jù)引用)的容器在不同窗體間傳遞,從而實(shí)現(xiàn)在彈出窗體中對(duì)數(shù)據(jù)的編輯

3.主細(xì)表

以上圖所示數(shù)據(jù)為例:

1)DataSet:myDataSet

2)DataTable:ParentTable、ChildTable、GrandChildTable

3)Relation:FK_Parent_Child、FK_Child_GrandChild

//綁定父數(shù)據(jù)

parentBindingSource.DataSource = myDataSet;

parentBindingSource.DataMember = "ParentTable";

m_GrandParentGrid.DataSource = m_GrandParentBindingSource;

//綁定子數(shù)據(jù)。
childBindingSource.DataSource = parentBindingSource;//綁定到“父BindingSource”,而不是父Table

childBindingSource.DataMember = "FK_Child_GrandChild";//綁定到“父-子Relation”

//綁定孫子數(shù)據(jù)。
grandChildBindingSource.DataSource = childBindingSource;//綁定到“子BindingSource”

grandChildBindingSource.DataMember = "FK_Child_GrandChild";//綁定到“子-孫Relation”

這樣你就可以在Form上擺上3個(gè)DataView,分布綁定到這3個(gè)BindingSouce,很容易就實(shí)現(xiàn)了主細(xì)表關(guān)聯(lián)展現(xiàn)。

4.數(shù)據(jù)操縱

要操縱數(shù)據(jù),首先需要獲取當(dāng)前數(shù)據(jù)項(xiàng)。BindingSource的Current屬性返回DataRowView類型的對(duì)象(就像DataView是對(duì)DataTable的封裝一樣,DataRowView是對(duì)DataRow的封裝),它是對(duì)當(dāng)前數(shù)據(jù)項(xiàng)的封裝,可以通過(guò)類型轉(zhuǎn)換變成你想要的對(duì)象。

DataRowView currentRowView = myBindingSource.Current;//獲取當(dāng)前RowView

CustomersRow custRow = currentRowView.Row as CustomersRow;//類型轉(zhuǎn)換為當(dāng)前數(shù)據(jù)項(xiàng)

string company = custRow.CompanyName;//使用當(dāng)前數(shù)據(jù)項(xiàng)

string phoneNo = custRow.Phone;

5.用BindingSource做數(shù)據(jù)容器

BindingSource還可以用作數(shù)據(jù)容器,即便它沒(méi)有綁定到數(shù)據(jù)源上,它內(nèi)部有一個(gè)可以容納數(shù)據(jù)的list。

5.1Add方法

調(diào)用Add方法會(huì)在BindingSource的list中插入數(shù)據(jù)項(xiàng)。如果這時(shí)第一次插入數(shù)據(jù),并且沒(méi)有綁定數(shù)據(jù),那么插入數(shù)據(jù)的類型就決定了今后此list中數(shù)據(jù)的類型。

注:

1)此時(shí)再插入其它類型對(duì)象會(huì)拋出InvalidOperationException異常

2)設(shè)置DataSource屬性時(shí)會(huì)刷新list,造成Add方法添加到list中的數(shù)據(jù)丟失

5.2AddNew方法

AddNew方法返回BindingSourc所容納數(shù)據(jù)類型的對(duì)象;如果之前沒(méi)有容納數(shù)據(jù),則會(huì)返回Object對(duì)象。

AddNew方法會(huì)調(diào)用EndEdit方法,并將提交對(duì)當(dāng)前數(shù)據(jù)的操縱;然后新數(shù)據(jù)項(xiàng)就成為當(dāng)前項(xiàng)。

AddNew方法會(huì)引發(fā)AddingNew事件,可以在此事件中為數(shù)據(jù)項(xiàng)賦值,或者創(chuàng)建新數(shù)據(jù)項(xiàng)

private void OnAddingNew(object sender, AddingNewEventArgs e)
{
????? e.NewObject = new MyCustomObject();//
}

6.用BindingSource對(duì)數(shù)據(jù)排序、過(guò)濾、搜索

6.1 Sort

為Sort屬性賦上Sort表達(dá)式,可以對(duì)數(shù)據(jù)進(jìn)行排序

myBindingSource.Sort = "ContactName ASC";//對(duì)ContanctName列按ASC進(jìn)行排序

myBindingSource.Sort = "Region ASC, CompanyName DESC"//先按Region、再按CompanyName排序

6.2 Find

Find方法根據(jù)指定屬性和關(guān)鍵字進(jìn)行查找,并返回第一個(gè)匹配對(duì)象的Index
int index = m_CustomersBindingSource.Find("CompanyName",IBM);//按CompanyName查找IBM
if (index != -1)
{
??? myBindingSource.Position = index;//定位BindingSource
}

6.3 Filter

為Filter屬性賦上表達(dá)式,可以對(duì)數(shù)據(jù)進(jìn)行過(guò)濾

m_CustomersBindingSource.Filter = "Country = 'Germany'";//過(guò)濾出Country屬性為Germany的數(shù)據(jù)

7.用Event監(jiān)控?cái)?shù)據(jù)

7.1 Event

1)AddingNew

調(diào)用AddNew()方法時(shí)觸發(fā)。

2)BindingComplete

當(dāng)控件完成數(shù)據(jù)綁定時(shí)觸發(fā),說(shuō)明控件已經(jīng)從數(shù)據(jù)源中讀取當(dāng)前數(shù)據(jù)項(xiàng)的值。當(dāng)BindingSource重新綁定或當(dāng)前數(shù)據(jù)項(xiàng)改變時(shí),會(huì)觸發(fā)此事件

注:

  • 當(dāng)有多個(gè)控件綁定到同一數(shù)據(jù)源時(shí),這個(gè)事件會(huì)觸發(fā)多次

3)CurrrentChanged

當(dāng)前數(shù)據(jù)項(xiàng)改變時(shí)觸發(fā)此事件。觸發(fā)此事件的情況如下

  • Position屬性改變時(shí)
  • 添加、刪除數(shù)據(jù)時(shí)
  • DataSource或DataMember屬性改變時(shí)

4)CurrentItemChanged

當(dāng)前數(shù)據(jù)項(xiàng)的值改變時(shí)觸發(fā)

5)DataError

通常輸入無(wú)效數(shù)據(jù)時(shí),由CurrencyManage拋出異常,從而觸發(fā)此事件。

6)PositionChanged

Position屬性改變時(shí)觸發(fā)此事件。

7)ListChanged

數(shù)據(jù)集合改變時(shí)觸發(fā)。觸發(fā)此事件的情況如下

  • adding, editing, deleting, 或 moving 數(shù)據(jù)項(xiàng)時(shí)

改變那些會(huì)影響List行為特征的屬性時(shí),如AllowEdit屬性

  • 替換List時(shí)(綁到新數(shù)據(jù)源)

8.限制數(shù)據(jù)修改

BindingSource不僅是數(shù)據(jù)源與控件間的“橋梁”,同時(shí)也是數(shù)據(jù)源的“看門人”。通過(guò)BindingSource,我們可以控制對(duì)數(shù)據(jù)的修改。

BinidingSource的AllowEdit, AllowNew和AllowRemove屬性可以控制客戶端代碼和控件對(duì)數(shù)據(jù)的修改

9.復(fù)雜數(shù)據(jù)類型的Binding

對(duì)于String類型的數(shù)據(jù),直接Binding到Text控件即可,對(duì)于復(fù)雜類型有下面幾種情況

  • 對(duì)于DateTime、Image等類型的數(shù)據(jù),它們存儲(chǔ)的格式與顯示要求并不一致。
  • 有時(shí),你并不想顯示客戶ID,而是希望顯示客戶名稱
  • 數(shù)據(jù)庫(kù)中的Null值

9.1 Binding類

解決以上問(wèn)題的關(guān)鍵是要理解Binding類,了解它是如何控制數(shù)據(jù)Binding的過(guò)程。

DataTable table = customersDataSet.Customers;

//將TextBox的Text屬性Binding到table的CustomerID列
customerIDTextBox.DataBindings.Add("Text", table,"CustomerID", true);

//上面一行代碼等同下面兩行代碼

Binding customerIDBinding = new Binding("Text", table,"CustomerID", true);
customerIDTextBox.DataBindings.Add(customerIDBinding);

從代碼可以看出,Binding是數(shù)據(jù)源(table)和控件(customerIDTextBox)間的中介人,它有以下功能

  • 從數(shù)據(jù)源取數(shù)據(jù),并按照控件要求的數(shù)據(jù)類型對(duì)此數(shù)據(jù)進(jìn)行格式化(Formatting),然后傳給控件
  • 從控件取數(shù)據(jù),并按照數(shù)據(jù)源的數(shù)據(jù)類型要求對(duì)此數(shù)據(jù)進(jìn)行解析(Parsing),然后返回給數(shù)據(jù)源
  • 自動(dòng)對(duì)數(shù)據(jù)進(jìn)行格式轉(zhuǎn)換

9.2Binding類構(gòu)造函數(shù)和屬性

Binding構(gòu)造函數(shù)有多個(gè)重載版本,下面介紹其重要的參數(shù),這些參數(shù)同時(shí)存在于Binding對(duì)象的屬性中。下面介紹中,參數(shù)名和屬性名都列出來(lái)

1)formattingEnabled(屬性FormattingEnabled)

  • ?
    • true,Binding對(duì)象自動(dòng)在數(shù)據(jù)源類型和控件要求的類型間進(jìn)行轉(zhuǎn)換
    • false,反之

2)dataSourceUpdateMode

決定控件上數(shù)值的改變?cè)诤螘r(shí)提交回?cái)?shù)據(jù)源

3)nullValue

DBNull、 null和Nullab<T>對(duì)應(yīng)的值。

4)formatString

格式轉(zhuǎn)換

5)formatInfo

一個(gè)實(shí)現(xiàn)IFormatProvider接口的對(duì)象引用,用來(lái)自定義格式轉(zhuǎn)換

要了解類型如何轉(zhuǎn)換的,請(qǐng)學(xué)習(xí)Type Conversions and Format Providers相關(guān)內(nèi)容。關(guān)于上面屬性的應(yīng)用,請(qǐng)看下面介紹

9.3基于Binding類的內(nèi)置機(jī)制(屬性、參數(shù))進(jìn)行類型轉(zhuǎn)換

通過(guò)Binding類構(gòu)造時(shí)的參數(shù),或?qū)傩栽O(shè)置,可以控制它進(jìn)行類型轉(zhuǎn)換的機(jī)制。

1)DateTime

下面先介紹一個(gè)DateTime類型的例子,使用DateTimePicker控件

//創(chuàng)建Binding,設(shè)置formattingEnabled為true

birthDateTimePicker.DataBindings.Add("Value",m_EmployeesBindingSource, "BirthDate", true);

//設(shè)定為使用自定義格式
birthDateTimePicker.Format = DateTimePickerFormat.Custom;

//設(shè)定格式
birthDateTimePicker.CustomFormat = "MM/dd/yyyy";

2)Numeric

salaryTextBox.DataBindings.Add("Text", employeesBindingSource,"Salary", true,? DataSourceUpdateMode.OnValidation,"<not specified>", "#.00");

以上代碼做了以下處理

  • 設(shè)定formattingEnabled為true:代表自動(dòng)類型轉(zhuǎn)換
  • 設(shè)定DataSourceUpdateMode為OnValidation:
  • 設(shè)定nullValue為"<not specified>":這些DBNull就顯示為,"<not specified>", 同時(shí)用戶錄入,"<not specified>"時(shí),數(shù)據(jù)值為DBNull
  • 設(shè)定formatString為"#.00":數(shù)值保留2位小數(shù)

9.4. 事件

下面介紹Binding的主要事件,以及如何基于這些事件進(jìn)行類型轉(zhuǎn)換的控制。

主要事件:

1)Format事件

發(fā)生在從數(shù)據(jù)源獲取數(shù)據(jù)后,控件顯示此數(shù)據(jù)之前。在這個(gè)事件里將數(shù)據(jù)源的數(shù)據(jù)類型轉(zhuǎn)換為控件要求的數(shù)據(jù)類型。

2)Parse事件

與Event相反。它發(fā)生控件值改變后,數(shù)據(jù)更新回?cái)?shù)據(jù)源之前。在這個(gè)事件里將控件的數(shù)據(jù)類型轉(zhuǎn)換為數(shù)據(jù)源要求的數(shù)據(jù)類型。

這兩個(gè)事件為我們控制數(shù)據(jù)提供了機(jī)制,它們都聲明為ConvertEventHandler類型,

void ConvertEventHandler(object sender, ConvertEventArgs e);

有兩個(gè)參數(shù),第二個(gè)參數(shù)ConvertEventArgs e 提供了我們要formatting和parsing的數(shù)據(jù)。它有兩個(gè)屬性

  • e.DesiredType是數(shù)值要轉(zhuǎn)換的目標(biāo)類型
  • e.Value是要轉(zhuǎn)換的數(shù)值。我們可以替換此Value

9.5. 基于事件的類型轉(zhuǎn)換

9.5.1 處理Format Event

void OnCountryFromFormat(object sender, ConvertEventArgs e)
{
??? if (e.Value == null || e.Value == DBNull.Value)
??? {
???????? pictureBox.Image = null;
???????? return;
??? }

??? //綁定的是數(shù)據(jù)源的CountryID字段,因此e.Value返回的ID號(hào),通過(guò)此ID號(hào)取得對(duì)應(yīng)數(shù)據(jù)行
??? CountriesRow countryRow =??? GetCountryRow((int)e.Value);

???? //將e.Value賦值為CountryName,從而在控件中顯示名稱
???? e.Value = countryRow.CountryName;
??? // 數(shù)據(jù)轉(zhuǎn)換

??? ImageConverter converter = new ImageConverter();
??? pictureBox.Image =??? converter.ConvertFrom(countryRow.Flag) as Image;
}

9.5.2 處理Format Event

void OnCountryFromParse(object sender, ConvertEventArgs e)
{
// Need to look up the Country information for the country name
ExchangeRatesDataSet.CountriesRow row =
GetCountryRow(e.Value.ToString());
if (row == null)
{
string error = "Country not found";
m_ErrorProvider.SetError(m_CountryFromTextBox, error);
m_CountryFromTextBox.Focus();
throw new ArgumentException(error);
}
e.Value = row.CountryID;
}

10 完成數(shù)據(jù)編輯

經(jīng)常會(huì)遇到這種情況,你在一個(gè)控件中錄入或選擇一些數(shù)據(jù),只有當(dāng)年離開此控件時(shí),關(guān)聯(lián)的數(shù)據(jù)才能同步更新。這個(gè)問(wèn)題是由DataRow內(nèi)部機(jī)制決定的。

DataRowView類實(shí)現(xiàn)IEditableObject接口,支持對(duì)象的事務(wù)性編輯(當(dāng)你確認(rèn)完成編輯前,可以回滾數(shù)據(jù))。我們通過(guò)BeginEdit()方法來(lái)開始數(shù)據(jù)編輯,通過(guò)EndEdit()方法提交編輯。

不要將DataRowView的EndEdit()與DataSet、DataTable、DataRow的AcceptChanges()方法混淆。DataRow有original和current版本,同時(shí)IEditableObject的caching機(jī)制讓它有transient版本,在調(diào)用EndEdit()方法前,數(shù)據(jù)修改是不會(huì)提交到數(shù)據(jù)源。這就是前面問(wèn)題的內(nèi)在原因。

如果希望編輯的數(shù)據(jù)立即提交,那調(diào)用EndEdit()函數(shù)的最佳位置就是Validated事件。Validate事件在控件錄入的數(shù)據(jù)parsed,并且通過(guò)validate后觸發(fā),在這個(gè)事件中觸發(fā)EndEdit()就會(huì)通知綁定到同一數(shù)據(jù)源的所有控件,從而實(shí)現(xiàn)數(shù)據(jù)同步更新。

private void OnCountryTextValidated(object sender, EventArgs e)
{
????????? exchangeRatesBindingSource.EndEdit();
}

當(dāng)然,當(dāng)前數(shù)據(jù)項(xiàng)改變時(shí),也會(huì)觸發(fā)EndEdit()事件

11 使用AutoComplete

當(dāng)你希望TexbBox或ComboBox中會(huì)自動(dòng)提示功能,那你應(yīng)該學(xué)習(xí)一下AutoComplete功能。下面以TextBox為例介紹相關(guān)步驟

1)設(shè)定TextBox的AutoCompleteSource屬性:FileSystem, HistoryList, RecentlyUsedList

2)如果希望使用自定義的列表,則設(shè)定AutoCompleteSource屬性為CustomSource

3)設(shè)定AutoCompleteMode為SuggestAppend。這意味著你輸入部分字符時(shí),控件在下拉列表中提示所有相近的數(shù)據(jù)

4)如果不想使用內(nèi)置的提示源,你可以自己創(chuàng)建一個(gè)AutoCompleteStringCollection類的列表,

5)創(chuàng)建這個(gè)列表后,將它賦給TextBox的AutoCompleteCustomSourc屬性

12 DataBinding的生命周期

BindingSource的DataSourceUpdateMode屬性是關(guān)鍵,它有以下三種可能值,下面分布以TextBox控件為例介紹此屬性不同時(shí)DataBinding的生命周期

1)OnValidating(缺省值)

  • DataBinding的生命周期:

TextBox.Leave, TextBox.Validating, Binding.Parse, TextBox.Validated

  • 此時(shí)若將控件的CausesValidation屬性設(shè)為false,那么Validating事件就不會(huì)發(fā)生

2)OnPropertyChanged

  • DataBinding的生命周期:

此時(shí),每次控件值發(fā)生改變時(shí)都會(huì)觸發(fā)Binding.Parse。對(duì)TextBox控件來(lái)說(shuō),每次錄入字符都會(huì)觸發(fā)Binding.Parse。

3)Never

此時(shí)Parse事件不會(huì)觸發(fā),也就是說(shuō)控件將成為只讀的。

13 子父綁定

前面介紹了主細(xì)綁定,它其實(shí)是一個(gè)父子綁定。有時(shí)我們希望由子到父的關(guān)聯(lián)綁定,下面我們就一起來(lái)實(shí)現(xiàn)這個(gè)機(jī)制。實(shí)現(xiàn)這個(gè)機(jī)制的關(guān)鍵還是Event,這個(gè)Event就是BindingSource的CurrentChanged事件

private void OnCurrentChanged(object sender, EventArgs e)
????? {
???????? // 獲取當(dāng)前的子DataRow
???????? ExchangeRatesDataSet.ExchangeRatesRow currentRow =
??????????? (ExchangeRatesDataSet.ExchangeRatesRow)
??????????? ((DataRowView)m_ExchangeRatesBindingSource.Current).Row;

???????? // 獲取關(guān)聯(lián)的父DataRow
???????? ExchangeRatesDataSet.CountriesRow fromCountryRow =
??????????? currentRow.CountriesRowByFK_ExchangeRates_CountriesFrom;
???????? ExchangeRatesDataSet.CountriesRow toCountryRow =
??????????? currentRow.CountriesRowByFK_ExchangeRates_CountriesTo;

???????? //顯示父DataRow的信息

???????? if (fromCountryRow != null && toCountryRow != null)
???????? {
??????????? m_FromCountryCombo.SelectedValue = fromCountryRow.CountryID;
??????????? m_ToCountryCombo.SelectedValue = toCountryRow.CountryID;
???????? }

}

14 綁定到數(shù)據(jù)的多個(gè)復(fù)本

有時(shí),我們希望以不同角度看到同一數(shù)據(jù),這時(shí)需要綁定到同一數(shù)據(jù)的多個(gè)復(fù)本。這里的關(guān)鍵是CurrencyManager類,每個(gè)BindingSource管理著一個(gè)CurrencyManager。如果多個(gè)控件綁定到同一個(gè)BindingSource,那么只有一個(gè)CurrencyManager,因此也就只有一個(gè)CurrentItem,這樣就造成這些綁定到同一BindingSource的控件同步刷新。要解決這個(gè)問(wèn)題,我們需要多個(gè)CurrencyManager,也就是說(shuō)我們可以創(chuàng)建多個(gè)BindingSource,且綁定到同一個(gè)數(shù)據(jù)源。

?轉(zhuǎn)自http://blog.csdn.net/cdhql/article/details/6129911

轉(zhuǎn)載于:https://www.cnblogs.com/yaojunyi/archive/2012/06/14/2549709.html

總結(jié)

以上是生活随笔為你收集整理的基于BindingSource的WinForm开发的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。