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.主细表

以上图所示数据为例:

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)

  • true,Binding对象自动在数据源类型和控件要求的类型间进行转换
  • 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是要转换的数值。我们可以替换此Value

9.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 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 完成数据编辑

经常会遇到这种情况,你在一个控件中录入或选择一些数据,只有当年离开此控件时,关联的数据才能同步更新。这个问题是由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, RecentlyUsedList

2)如果希望使用自定义的列表,则设定AutoCompleteSource属性为CustomSource

3)设定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,且绑定到同一个数据源。

转自http://blog.csdn.net/cdhql/article/details/6129911

转载于:https://www.cnblogs.com/yaojunyi/archive/2012/06/14/2549709.html

基于BindingSource的WinForm开发相关推荐

  1. 画多个矩形c语言,C# winform开发:Graphics、pictureBox同时画多个矩形

    C#的System.Drawing 命名空间提供了对 GDI+ 基本图形功能的访问 重点在于获取Graphics对象,例如: Graphics g = panel1.CreateGraphics 事实 ...

  2. 基于.Net进行前端开发的技术栈发展路线(一)

    前言 今天想讲讲的是我的技术树.我最初是做CS开发的,第一阶段的技术经历是以Powerbuilder来做CS开发,第二阶段开始基于C#做winform开发,眼看前端开发越来越流行,需要更广泛的技术栈势 ...

  3. 基于OpenCV+WinForm开发的图形图像渲染控件

    基于OpenCV+WinForm开发的图形图像渲染控件 WinForm版图形图像渲染控件 图像居中渲染 图像放大 图像缩小 绘制图形 点 线 矩形 圆形 旋转矩形 多边形 资源连接 WinForm版图 ...

  4. Winform开发的界面处理优化

    在Winform开发中,客户体验是个很好的参考性指标,如果一个功能使用的时候感觉很流畅,说明我们的程序执行效率还不错,但是随着数据的真多,原先可能流程的地方可能会变得比较卡,这时候就需要追本索源,找到 ...

  5. Winform开发几个常用的开发经验及知识积累(一)

    本人做Winform开发多年,孜孜不倦,略有小成,其中收集或者自己开发一些常用的东西,基本上在各个项目都能用到的一些开发经验及知识积累,现逐步介绍一些,以飨读者,共同进步.  1.窗口[×]关闭按钮变 ...

  6. MapServer WinForm开发成功

    mapServer的ms4w现在的最新版本是基于.net1.1,前两天基于.net 2,使用asp.net2成功建成了一个网站(虽然性能不弱),各种功能都正常使用,心想应该能够制作一个WinForm版 ...

  7. [转载]C# WinForm开发系列 - 文章索引

    该系列主要整理收集在使用C#开发WinForm应用文章及相关代码, 平时看到大家主要使用C#来开发Asp.Net应用,这方面的文章也特别多,而关于WinForm的文章相对少很多,而自己对WinForm ...

  8. C# WinForm开发系列 - Open-Source Controls

    整理了一些在WinForm开发中可以使用的开源组件.(文章及相关代码搜集自网络,仅供学习参考,版权属于原作者! ). 1. 仿office 2007的Ribbon风格面板(该控件模仿office 20 ...

  9. VS2017 winform开发知识点汇总

    VS2017 winform开发知识点汇总 1 快捷键 2 控键缩写 2.1 标准控件 2.2 容器控件 2.3 菜单和工具栏 2.4 数据 2.5 对话框 2.6 组件 2.7 印刷 2.8 水晶报 ...

最新文章

  1. docker mysql详解_Docker轻松入门(详解)
  2. LeetCode Sort Characters By Frequency
  3. 大熊君说说JS与设计模式之(门面模式Facade)迪米特法则的救赎篇------(监狱的故事)...
  4. 深圳30周年看×××之旅
  5. 常见.Net 英文专业词汇收集
  6. Swift 2.0初探:值得注意的新特性
  7. 最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用41
  8. c语言api文档_初学 C 语言没有项目练手?这 20 个小项目拿走不谢
  9. 手工matlab下K-means聚类算法实现而不是调用库函数
  10. 德州扑克的思考和实验
  11. atitit.MyEclipse10 中增加svn插件故障排除
  12. PMP培训机构怎么选?
  13. MFC控件之cimagelist,加载不上位图
  14. websocket报错:java.io.EOFException: null
  15. 用fft对信号进行频谱分析实验报告_【鼎阳硬件智库原创︱测试测量 】基于全数字中频技术频谱分析仪的工作原理...
  16. 编写热血江湖模拟按键外挂
  17. xcode 中生成和打包 ipa文件的方法和步骤
  18. 计算机的单位换算字节,关于计算机的存储字节单位换算和使用
  19. 四核处理器_一千块普通办公电脑配置清单,还是四核处理器,能玩TX全家桶
  20. android记账本折线图_小熊记账本

热门文章

  1. 2019年Vue学习路线图
  2. 对Java Inputstream的一次采访
  3. redis:list的底层实现--压缩列表
  4. 47.命名空间namespace
  5. 剑指offer:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
  6. C语言的成绩查询系统,c语言 成绩查询系统
  7. word受权限保护无法打开_双击文档无法打开到底是啥毛病?简单一招解决
  8. 7000更换控制器电源步骤_恒温恒湿试验箱几大故障的检查步骤及解决方法说明...
  9. 成功解决 Exception: URL fetch failure on https://s3.amazonaws.com/img-datasets/mnist.npz: None -- [Errno
  10. 成功解决ValueError: setting an array element with a sequence.