C# BindingSource

來源:互聯網
上載者:User
1.引言BindingSource組件是資料來源和控制項間的一座橋,同時提供了大量的API和Event供我們使用。使用這些API我們可以將Code與各種具體類型資料來源進行解耦;使用這些Event我們可以洞察資料的變化。2.簡單綁定    DataTable myTable = myTableAdapter.GetData();//建立Table    BindingSource myBindingSource= new BindingSource();//建立BindingSource    DataGridView myGrid = new DataGridView();//建立GridView    myGrid.DataSource = myBindingSource;//將BindingSource綁定到GridView    myTable;//綁定資料到BindingSource    註:    1)綁定到DataTable,其實是綁定到DataTable提供的DataView上。每個DataTable都有一個預設的DataView    2)DataView是綁定的實質,正如其名,它是DataTable的資料的展現。因此可以對同一個DataTable    ,構建多個DataView,進而可以對這同樣的資料實施不同的過濾、排序等方法,從不同側面展示DataTable。這也體現了一定的MVC思想。    3)BindingSouce也可作為資料(其實是資料引用)的容器在不同表單間傳遞,從而實現在彈出表單中對資料的編輯 3.主細表    image    以所示資料為例:    1)DataSet:myDataSet    2)DataTable:ParentTable、ChildTable、GrandChildTable    3)Relation:FK_Parent_Child、FK_Child_GrandChild    //綁定父資料    parentBindingSource.DataSource = myDataSet;    parentBindingSource.DataMember = "ParentTable";    m_GrandParentGrid.DataSource = m_GrandParentBindingSource;    //綁定子資料。    childBindingSource.DataSource = parentBindingSource;//綁定到“父BindingSource”,而不是父Table    childBindingSource.DataMember = "FK_Child_GrandChild";//綁定到“父-子Relation”    //綁定孫子資料。    grandChildBindingSource.DataSource = childBindingSource;//綁定到“子BindingSource”    grandChildBindingSource.DataMember = "FK_Child_GrandChild";//綁定到“子-孫Relation”這樣你就可以在Form上擺上3個DataView,分布綁定到這3個BindingSouce,很容易就實現了主細表關聯展現。4.資料操縱要操縱資料,首先需要擷取當前資料項目。BindingSource的Current屬性返回DataRowView類型的對象(就像DataView是對 DataTable的封裝一樣,DataRowView是對DataRow的封裝),它是對當前資料項目的封裝,可以通過類型轉換變成你想要的對象。    DataRowView currentRowView = myBindingSource.Current;//擷取當前RowView    CustomersRow custRow = currentRowView.Row as CustomersRow;//類型轉換為當前資料項目    string company = custRow.CompanyName;//使用當前資料項目    string phoneNo = custRow.Phone;5.用BindingSource做資料容器BindingSource還可以用作資料容器,即便它沒有綁定到資料來源上,它內部有一個可以容納資料的list。5.1Add方法調用Add方法會在BindingSource的list中插入資料項目。如果這時第一次插入資料,並且沒有綁定資料,那麼插入資料的類型就決定了今後此list中資料的類型。    註:    1)此時再插入其它類型對象會拋出InvalidOperationException異常    2)設定DataSource屬性時會重新整理list,造成Add方法添加到list中的資料丟失5.2AddNew方法AddNew方法返回BindingSourc所容納資料類型的對象;如果之前沒有容納資料,則會返回Object對象。AddNew方法會調用EndEdit方法,並將提交對當前資料的操縱;然後新資料項目就成為當前項。AddNew方法會引發AddingNew事件,可以在此事件中為資料項目賦值,或者建立新資料項目    private void OnAddingNew(object sender, AddingNewEventArgs e)    {          e.NewObject = new MyCustomObject();//    }6.用BindingSource對資料排序、過濾、搜尋6.1 Sort為Sort屬性賦上Sort運算式,可以對資料進行排序    myBindingSource.Sort = "ContactName ASC";//對ContanctName列按ASC進行排序    myBindingSource.Sort = "Region ASC, CompanyName DESC"//先按Region、再按CompanyName排序6.2 Find    Find方法根據指定屬性和關鍵字進行尋找,並返回第一個匹配對象的Index    int index = m_CustomersBindingSource.Find("CompanyName",IBM);//按CompanyName尋找IBM    if (index != -1)    {        myBindingSource.Position = index;//定位BindingSource    }6.3 Filter為Filter屬性賦上運算式,可以對資料進行過濾    m_CustomersBindingSource.Filter = "Country = 'Germany'";//過濾出Country屬性為Germany的資料7.用Event監控資料7.1 Event    1)AddingNew    調用AddNew()方法時觸發。    2)BindingComplete    當控制項完成資料繫結時觸發,說明控制項已經從資料來源中讀取當前資料項目的值。當BindingSource重新綁定或當前資料項目改變時,會觸發此事件    註:        * 當有多個控制項綁定到同一資料來源時,這個事件會觸發多次    3)CurrrentChanged    當前資料項目改變時觸發此事件。觸發此事件的情況如下        * Position屬性改變時        * 添加、刪除資料時        * DataSource或DataMember屬性改變時    4)CurrentItemChanged    當前資料項目的值改變時觸發    5)DataError    通常輸入無效資料時,由CurrencyManage拋出異常,從而觸發此事件。    6)PositionChanged    Position屬性改變時觸發此事件。    7)ListChanged    資料集合改變時觸發。觸發此事件的情況如下        * adding, editing, deleting, 或 moving 資料項目時    改變那些會影響List行為特徵的屬性時,如AllowEdit屬性        * 替換List時(綁到新資料來源)8.限制資料修改BindingSource不僅是資料來源與控制項間的“橋樑”,同時也是資料來源的“看門人”。通過BindingSource,我們可以控制對資料的修改。BinidingSource的AllowEdit, AllowNew和AllowRemove屬性可以控制用戶端代碼和控制項對資料的修改9.複雜資料類型的Binding對於String類型的資料,直接Binding到Text控制項即可,對於複雜類型有下面幾種情況    * 對於DateTime、Image等類型的資料,它們儲存的格式與顯示要求並不一致。    * 有時,你並不想顯示客戶ID,而是希望顯示客戶名稱    * 資料庫中的Null值9.1 Binding類解決以上問題的關鍵是要理解Binding類,瞭解它是如何控制資料Binding的過程。    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是資料來源(table)和控制項(customerIDTextBox)間的中介人,它有以下功能    * 從資料來源取資料,並按照控制項要求的資料類型對此資料進行格式化(Formatting),然後傳給控制項    * 從控制項取資料,並按照資料來源的資料類型要求對此資料進行解析(Parsing),然後返回給資料來源    * 自動對資料進行格式轉換9.2Binding類建構函式和屬性Binding建構函式有多個重載版本,下面介紹其重要的參數,這些參數同時存在於Binding對象的屬性中。下面介紹中,參數名和屬性名稱都列出來    1)formattingEnabled(屬性FormattingEnabled)          o true,Binding對象自動在資料來源類型和控制項要求的類型間進行轉換          o false,反之    2)dataSourceUpdateMode    決定控制項上數值的改變在何時提交回資料來源    3)nullValue    DBNull、 null和Nullab<T>對應的值。    4)formatString    格式轉換    5)formatInfo    一個實現IFormatProvider介面的對象引用,用來自訂格式轉換要瞭解類型如何轉換的,請學習Type Conversions and Format Providers相關內容。關於上面屬性的應用,請看下面介紹9.3基於Binding類的內建機制(屬性、參數)進行類型轉換通過Binding類構造時的參數,或屬性設定,可以控制它進行類型轉換的機制。1)DateTime下面先介紹一個DateTime類型的例子,使用DateTimePicker控制項    //建立Binding,設定formattingEnabled為true    birthDateTimePicker.DataBindings.Add("Value",m_EmployeesBindingSource, "BirthDate", true);    //設定為使用自訂格式    birthDateTimePicker.Format = DateTimePickerFormat.Custom;    //設定格式    birthDateTimePicker.CustomFormat = "MM/dd/yyyy";2)Numeric    salaryTextBox.DataBindings.Add("Text", employeesBindingSource,"Salary", true,  DataSourceUpdateMode.OnValidation,"<not specified>", "#.00");    以上代碼做了以下處理        * 設定formattingEnabled為true:代表自動類型轉換        * 設定DataSourceUpdateMode為OnValidation:        * 設定nullValue為"<not specified>":這些DBNull就顯示為,"<not specified>", 同時使用者錄入,"<not specified>"時,資料值為DBNull        * 設定formatString為"#.00":數值保留2位小數9.4. 事件下面介紹Binding的主要事件,以及如何基於這些事件進行類型轉換的控制。主要事件:1)Format事件發生在從資料來源擷取資料後,控制項顯示此資料之前。在這個事件裡將資料來源的資料類型轉換為控制項要求的資料類型。2)Parse事件與Event相反。它發生控制項值改變後,資料更新回資料來源之前。在這個事件裡將控制項的資料類型轉換為資料來源要求的資料類型。這兩個事件為我們控制資料提供了機制,它們都聲明為ConvertEventHandler類型,    void ConvertEventHandler(object sender, ConvertEventArgs e);有兩個參數,第二個參數ConvertEventArgs e 提供了我們要formatting和parsing的資料。它有兩個屬性    * e.DesiredType是數值要轉換的目標類型    * e.Value是要轉換的數值。我們可以替換此Value9.5. 基於事件的類型轉換9.5.1 處理Format Event    void OnCountryFromFormat(object sender, ConvertEventArgs e)    {        if (e.Value == null || e.Value == DBNull.Value)        {             pictureBox.Image = null;             return;        }        //綁定的是資料來源的CountryID欄位,因此e.Value返回的ID號,通過此ID號取得對應資料行        CountriesRow countryRow =    GetCountryRow((int)e.Value);         //將e.Value賦值為CountryName,從而在控制項中顯示名稱         e.Value = countryRow.CountryName;        // 資料轉換        ImageConverter converter = new ImageConverter();        pictureBox.Image =    converter.ConvertFrom(countryRow.Flag) as Image;    }9.5.2 處理Format Eventvoid OnCountryFromParse(object sender, ConvertEventArgs e){// Need to look up the Country information for the country nameExchangeRatesDataSet.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 完成資料編輯經常會遇到這種情況,你在一個控制項中錄入或選擇一些資料,只有當年離開此控制項時,關聯的資料才能同步更新。這個問題是由DataRow內部機制決定的。DataRowView類實現IEditableObject介面,支援對象的事務性編輯(當你確認完成編輯前,可以復原資料)。我們通過BeginEdit()方法來開始資料編輯,通過EndEdit()方法提交編輯。不要將DataRowView的EndEdit()與DataSet、DataTable、DataRow的AcceptChanges()方法混淆。 DataRow有original和current版本,同時IEditableObject的caching機制讓它有transient版本,在調用 EndEdit()方法前,資料修改是不會提交到資料來源。這就是前面問題的內在原因。如果希望編輯的資料立即提交,那調用 EndEdit()函數的最佳位置就是Validated事件。Validate事件在控制項錄入的資料parsed,並且通過validate後觸發,在這個事件中觸發EndEdit()就會通知綁定到同一資料來源的所有控制項,從而實現資料同步更新。    private void OnCountryTextValidated(object sender, EventArgs e)    {              exchangeRatesBindingSource.EndEdit();    }當然,當前資料項目改變時,也會觸發EndEdit()事件11 使用AutoComplete當你希望TexbBox或ComboBox中會自動提示功能,那你應該學習一下AutoComplete功能。下面以TextBox為例介紹相關步驟1)設定TextBox的AutoCompleteSource屬性:FileSystem, HistoryList, RecentlyUsedList2)如果希望使用自訂的列表,則設定AutoCompleteSource屬性為CustomSource3)設定AutoCompleteMode為SuggestAppend。這意味著你輸入部分字元時,控制項在下拉式清單中提示所有相近的資料4)如果不想使用內建的提示源,你可以自己建立一個AutoCompleteStringCollection類的列表,5)建立這個列表後,將它賦給TextBox的AutoCompleteCustomSourc屬性12 DataBinding的生命週期BindingSource的DataSourceUpdateMode屬性是關鍵,它有以下三種可能值,下面分布以TextBox控制項為例介紹此屬性不同時DataBinding的生命週期1)OnValidating(預設值)    * DataBinding的生命週期:    TextBox.Leave, TextBox.Validating, Binding.Parse, TextBox.Validated    * 此時若將控制項的CausesValidation屬性設為false,那麼Validating事件就不會發生2)OnPropertyChanged    * DataBinding的生命週期:    此時,每次控制項值發生改變時都會觸發Binding.Parse。對TextBox控制項來說,每次錄入字元都會觸發Binding.Parse。3)Never    此時Parse事件不會觸發,也就是說控制項將成為唯讀。13 子父綁定前面介紹了主細綁定,它其實是一個父子綁定。有時我們希望由子到父的關聯綁定,下面我們就一起來實現這個機制。實現這個機制的關鍵還是Event,這個Event就是BindingSource的CurrentChanged事件    private void OnCurrentChanged(object sender, EventArgs e)          {             // 擷取當前的子DataRow             ExchangeRatesDataSet.ExchangeRatesRow currentRow =                (ExchangeRatesDataSet.ExchangeRatesRow)                ((DataRowView)m_ExchangeRatesBindingSource.Current).Row;             // 擷取關聯的父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 綁定到資料的多個複本有 時,我們希望以不同角度看到同一資料,這時需要綁定到同一資料的多個複本。這裡的關鍵是CurrencyManager類,每個 BindingSource管理著一個CurrencyManager。如果多個控制項綁定到同一個BindingSource,那麼只有一個 CurrencyManager,因此也就只有一個CurrentItem,這樣就造成這些綁定到同一BindingSource的控制項同步重新整理。要解決這個問題,我們需要多個CurrencyManager,也就是說我們可以建立多個BindingSource,且綁定到同一個資料來源。  9.5 處理Null類型這裡有兩個概念要弄清楚,.Net內建的Null類型與代表資料庫中的Null類型,以及它們的區別。    1).Net內建的Null類型        * Nullable,參考型別        * Nuallable<T>,實值型別    2).Net用來代表資料庫中的Null類型        * DBNull,它有一個屬性Value,可以用來判斷資料是否為DBNull              if (northwindDataSet.Employees[0].Country == DBNull.Value)             {                     // Handle null case here              }             對強型別資料集    if (northwindDataSet.Employees[0].IsCountryNull())    {    // Handle null case here    } 1)AddNew()函數:用來添加一條資料,傳回型別由綁定的DataSource決定。    1)綁定到DataSet/DataTable時,返回DataRowView對象。    注意:          a)返回的不是DataSet或DataTable或DataRow。          b)如果希望擷取添加的資料,需要進行類型轉換               //bs為你建立的BindingSource              DataRow row=(DataRow)((DataRowView) bs.AddNew()).Row;           c)使用TypedDataSet時,轉換方法與上面類似,只是用TypedDataRow而已             //MyDataRow為你定義的TypedDataRow              MyDataRow row=(MyDataRow)((DataRowView) bs.AddNew()).Row;
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.