C# 中BindingSource 的用法
.引言 BindingSource组件是数据源和控件间的一座桥,同时提供了大量的API和Event供我们使用。使用这些API我们可以将Code与各种具体类型数据源进行解耦;使用这些Event我们可以洞察数据的变化。
.简单绑定 DataTable myTable = myTableAdapter.GetData();//创建Table BindingSource myBindingSource= new BindingSource();//创建BindingSource DataGridView myGrid = new DataGridView();//创建GridView myGrid.DataSource = myBindingSource;//将BindingSource绑定到GridView myTable;//绑定数据到BindingSource 注: )绑定到DataTable,其实是绑定到DataTable提供的DataView上。每个DataTable都有一个缺省的DataView )DataView是绑定的实质,正如其名,它是DataTable的数据的展现。因此可以对同一个DataTable ,构建多个DataView,进而可以对这同样的数据实施不同的过滤、排序等方法,从不同侧面展示DataTable。这也体现了一定的MVC思想。 )BindingSouce也可作为数据(其实是数据引用)的容器在不同窗体间传递,从而实现在弹出窗体中对数据的编辑 .主细表 image 以上图所示数据为例: )DataSet:myDataSet )DataTable:ParentTable、ChildTable、GrandChildTable )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,很容易就实现了主细表关联展现。
.数据操纵
要操纵数据,首先需要获取当前数据项。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; .用BindingSource做数据容器 BindingSource还可以用作数据容器,即便它没有绑定到数据源上,它内部有一个可以容纳数据的list。
.1Add方法 调用Add方法会在BindingSource的list中插入数据项。如果这时第一次插入数据,并且没有绑定数据,那么插入数据的类型就决定了今后此list中数据的类型。 注: )此时再插入其它类型对象会抛出InvalidOperationException异常 )设置DataSource属性时会刷新list,造成Add方法添加到list中的数据丢失 .2AddNew方法 AddNew方法返回BindingSourc所容纳数据类型的对象;如果之前没有容纳数据,则会返回Object对象。 AddNew方法会调用EndEdit方法,并将提交对当前数据的操纵;然后新数据项就成为当前项。 AddNew方法会引发AddingNew事件,可以在此事件中为数据项赋值,或者创建新数据项 private void OnAddingNew(object sender, AddingNewEventArgs e)
{
e.NewObject = new MyCustomObject();//
} .用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 != -)
{
myBindingSource.Position = index;//定位BindingSource
} 6.3 Filter 为Filter属性赋上表达式,可以对数据进行过滤 m_CustomersBindingSource.Filter = "Country = 'Germany'";//过滤出Country属性为Germany的数据 .用Event监控数据
7.1 Event )AddingNew 调用AddNew()方法时触发。 )BindingComplete 当控件完成数据绑定时触发,说明控件已经从数据源中读取当前数据项的值。当BindingSource重新绑定或当前数据项改变时,会触发此事件 注: * 当有多个控件绑定到同一数据源时,这个事件会触发多次 )CurrrentChanged 当前数据项改变时触发此事件。触发此事件的情况如下 * Position属性改变时
* 添加、删除数据时
* DataSource或DataMember属性改变时 )CurrentItemChanged 当前数据项的值改变时触发 )DataError 通常输入无效数据时,由CurrencyManage抛出异常,从而触发此事件。 )PositionChanged Position属性改变时触发此事件。 )ListChanged 数据集合改变时触发。触发此事件的情况如下 * adding, editing, deleting, 或 moving 数据项时 改变那些会影响List行为特征的属性时,如AllowEdit属性 * 替换List时(绑到新数据源) .限制数据修改 BindingSource不仅是数据源与控件间的“桥梁”,同时也是数据源的“看门人”。通过BindingSource,我们可以控制对数据的修改。 BinidingSource的AllowEdit, AllowNew和AllowRemove属性可以控制客户端代码和控件对数据的修改
.复杂数据类型的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),然后返回给数据源
* 自动对数据进行格式转换 .2Binding类构造函数和属性 Binding构造函数有多个重载版本,下面介绍其重要的参数,这些参数同时存在于Binding对象的属性中。下面介绍中,参数名和属性名都列出来 )formattingEnabled(属性FormattingEnabled) o true,Binding对象自动在数据源类型和控件要求的类型间进行转换
o false,反之 )dataSourceUpdateMode 决定控件上数值的改变在何时提交回数据源 )nullValue DBNull、 null和Nullab<T>对应的值。 )formatString 格式转换 )formatInfo 一个实现IFormatProvider接口的对象引用,用来自定义格式转换 要了解类型如何转换的,请学习Type Conversions and Format Providers相关内容。关于上面属性的应用,请看下面介绍
.3基于Binding类的内置机制(属性、参数)进行类型转换 通过Binding类构造时的参数,或属性设置,可以控制它进行类型转换的机制。 )DateTime 下面先介绍一个DateTime类型的例子,使用DateTimePicker控件 //创建Binding,设置formattingEnabled为true birthDateTimePicker.DataBindings.Add("Value",m_EmployeesBindingSource, "BirthDate", true); //设定为使用自定义格式
birthDateTimePicker.Format = DateTimePickerFormat.Custom; //设定格式
birthDateTimePicker.CustomFormat = "MM/dd/yyyy"; )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的主要事件,以及如何基于这些事件进行类型转换的控制。 主要事件: )Format事件 发生在从数据源获取数据后,控件显示此数据之前。在这个事件里将数据源的数据类型转换为控件要求的数据类型。 )Parse事件 与Event相反。它发生控件值改变后,数据更新回数据源之前。在这个事件里将控件的数据类型转换为数据源要求的数据类型。 这两个事件为我们控制数据提供了机制,它们都声明为ConvertEventHandler类型, void ConvertEventHandler(object sender, ConvertEventArgs e); 有两个参数,第二个参数ConvertEventArgs e 提供了我们要formatting和parsing的数据。它有两个属性 * e.DesiredType是数值要转换的目标类型
* e.Value是要转换的数值。我们可以替换此Value 9.5. 基于事件的类型转换
9.5. 处理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. 处理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;
}
完成数据编辑 经常会遇到这种情况,你在一个控件中录入或选择一些数据,只有当年离开此控件时,关联的数据才能同步更新。这个问题是由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()事件
使用AutoComplete 当你希望TexbBox或ComboBox中会自动提示功能,那你应该学习一下AutoComplete功能。下面以TextBox为例介绍相关步骤 )设定TextBox的AutoCompleteSource属性:FileSystem, HistoryList, RecentlyUsedList )如果希望使用自定义的列表,则设定AutoCompleteSource属性为CustomSource )设定AutoCompleteMode为SuggestAppend。这意味着你输入部分字符时,控件在下拉列表中提示所有相近的数据 )如果不想使用内置的提示源,你可以自己创建一个AutoCompleteStringCollection类的列表, )创建这个列表后,将它赋给TextBox的AutoCompleteCustomSourc属性
DataBinding的生命周期 BindingSource的DataSourceUpdateMode属性是关键,它有以下三种可能值,下面分布以TextBox控件为例介绍此属性不同时DataBinding的生命周期 )OnValidating(缺省值) * DataBinding的生命周期: TextBox.Leave, TextBox.Validating, Binding.Parse, TextBox.Validated * 此时若将控件的CausesValidation属性设为false,那么Validating事件就不会发生 )OnPropertyChanged * DataBinding的生命周期: 此时,每次控件值发生改变时都会触发Binding.Parse。对TextBox控件来说,每次录入字符都会触发Binding.Parse。 )Never 此时Parse事件不会触发,也就是说控件将成为只读的。 子父绑定 前面介绍了主细绑定,它其实是一个父子绑定。有时我们希望由子到父的关联绑定,下面我们就一起来实现这个机制。实现这个机制的关键还是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;
} } 绑定到数据的多个复本 有 时,我们希望以不同角度看到同一数据,这时需要绑定到同一数据的多个复本。这里的关键是CurrencyManager类,每个 BindingSource管理着一个CurrencyManager。如果多个控件绑定到同一个BindingSource,那么只有一个 CurrencyManager,因此也就只有一个CurrentItem,这样就造成这些绑定到同一BindingSource的控件同步刷新。要解决这个问题,我们需要多个CurrencyManager,也就是说我们可以创建多个BindingSource,且绑定到同一个数据源。 9.5 处理Null类型 这里有两个概念要弄清楚,.Net内置的Null类型与代表数据库中的Null类型,以及它们的区别。 ).Net内置的Null类型 * Nullable,引用类型
* Nuallable<T>,值类型 ).Net用来代表数据库中的Null类型 * DBNull,它有一个属性Value,可以用来判断数据是否为DBNull if (northwindDataSet.Employees[].Country == DBNull.Value)
{
// Handle null case here
} 对强类型数据集 if (northwindDataSet.Employees[].IsCountryNull())
{
// Handle null case here
} )AddNew()函数:用来添加一条数据,返回类型由绑定的DataSource决定。 )绑定到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;
C# 中BindingSource 的用法的更多相关文章
- [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法
一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...
- C#中string.format用法详解
C#中string.format用法详解 本文实例总结了C#中string.format用法.分享给大家供大家参考.具体分析如下: String.Format 方法的几种定义: String.Form ...
- SQL中distinct的用法
SQL中distinct的用法 1.作用于单列 2.作用于多列 3.COUNT统计 4.distinct必须放在开头 5.其他 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出 ...
- Oracle 中 decode 函数用法
Oracle 中 decode 函数用法 含义解释:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF 条件=值1 THEN RETURN(翻译 ...
- jQuery中Animate进阶用法(一)
jQuery中animate的用法你了解多少呢?如果仅仅是简单的移动位置,显示隐藏,哦!天哪你在浪费资源!因为animate太强大了,你可以有很多意想不到的用法!让我们一起研究一下吧~~ 首先要了解j ...
- [转载]js中return的用法
一.返回控制与函数结果,语法为:return 表达式; 语句结束函数执行,返回调用函数,而且把表达式的值作为函数的结果 二.返回控制,无函数结果,语法为:return; 在大多数情况下,为事件处理函 ...
- js中this的用法
经过近几周的模拟面试题,我查询了一些资料,今天就来说说,在js中this的用法吧.方法有四:第一,用作全局变量,第二,用作表该对象,第三,用作构造函数,第四,用作call和applay
- jQuery中eq()方法用法实例
本文实例讲述了jQuery中eq()方法用法.分享给大家供大家参考.具体分析如下: 此方法能够获取匹配元素集上的相应位置索引的元素. 匹配元素集上元素的位置索引是从0开始的. 语法结构: 复制代码 代 ...
- php中return的用法实例分析
本文实例讲述了php中return的用法.分享给大家供大家参考.具体分析如下: 首先,它的意思就是返回;return()是语言结构而不是函数,仅在参数包含表达式时才需要用括号将其括起来.当返回一个变量 ...
随机推荐
- swagger2访问url
swagger : http://localhost:8080/swagger/index.html springboot中的swagger:http://localhost:8080/swagger ...
- unzip文件解压
1.记录下,遇到.zip的安装包,指定解压到某个地方 格式:unzip 压缩包名.zip -d 存放路径
- C. cltt的幸运数LCAdfs
/*C: cltt的幸运数 Time Limit: 1 s Memory Limit: 128 MB Submit Problem Description 一棵树有n个节点,共m次查询,查询 ...
- last与lastb命令 读取的日志文件
在linux系统中,last与lastb命令用来列出目前与过去登录系统的用户相关信息.指令英文原义: last, lastb - show listing of last logged in user ...
- python--使用递归的方式建立二叉树
树和图的数据结构,就很有意思啦. # coding = utf-8 class BinaryTree: def __init__(self, root_obj): self.key = root_ob ...
- C# Enum,Int,String的互相转换 [转]
C# Enum,Int,String的互相转换 Enum为枚举提供基类,其基础类型可以是除 Char 外的任何整型.如果没有显式声明基础类型,则使用 Int32.编程语言通常提供语法来声明由一组已命名 ...
- nginx 日志 cron任务切割日志
#vim cut_nginx_log.sh #cd /usr/local/nginx/logs/ #/bin/mv access.log access_$(date +%F).log #/usr/lo ...
- 本地化KendoUI
<!doctype html> <html> <head> <title>Kendo UI Web</title> ...
- 扩展中国剩余定理 (exCRT) 的证明与练习
原文链接https://www.cnblogs.com/zhouzhendong/p/exCRT.html 扩展中国剩余定理 (exCRT) 的证明与练习 问题模型 给定同余方程组 $$\begin{ ...
- 如何使用java代码启动tomcat和打开浏览器
1.用于代码启动tomcat,也可以用代码运行电脑应用程序 public static void main(String[] args) { /* new MyThread().start(); ne ...